45#include <kcalcore/visitor.h>
46using namespace KCalCore;
48#include <kpimidentities/identitymanager.h>
50#include <kpimutils/email.h>
51#include <kpimutils/linklocator.h>
53#include <KCalendarSystem>
56#include <KLocalizedString>
59#include <KSystemTimeZone>
61#include <QtCore/QBitArray>
62#include <QApplication>
64#include <QTextDocument>
66using namespace KCalUtils;
67using namespace IncidenceFormatter;
74static QString string2HTML(
const QString &str)
78 return KPIMUtils::LinkLocator::convertToHtml(str);
81static KPIMIdentities::IdentityManager *s_identityManager = 0;
85struct RAIIIdentityManager{
89 s_identityManager =
new KPIMIdentities::IdentityManager(
true);
92 ~RAIIIdentityManager()
94 delete s_identityManager;
95 s_identityManager = 0;
101static bool thatIsMe(
const QString &email)
103 return s_identityManager ? s_identityManager->thatIsMe(email)
104 : KPIMIdentities::IdentityManager(
true).thatIsMe(email);
110 return thatIsMe(attendee->email());
113static bool iamPerson(
const Person &person)
116 return thatIsMe(person.
email());
119static QString htmlAddLink(
const QString &ref,
const QString &text,
122 QString tmpStr(QLatin1String(
"<a href=\"") + ref + QLatin1String(
"\">") + text + QLatin1String(
"</a>"));
124 tmpStr += QLatin1Char(
'\n');
129static 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(
"\">"));
153static 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);
169static 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(
'>');
193static QPair<QString, QString> searchNameAndUid(
const QString &email,
const QString &name,
199 QPair<QString, QString>s;
202 if (!email.isEmpty() && (name.isEmpty() || uid.isEmpty())) {
208static QString searchName(
const QString &email,
const QString &name)
210 const QString printName = name.isEmpty() ? email : name;
222 return thatIsMe(incidence->organizer()->email());
225static 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())) {
255static 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()) {
277static 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);
340static 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);
371static QString displayViewFormatPerson(
const QString &email,
const QString &name,
374 return displayViewFormatPerson(email, name, uid, rsvpStatusIconPath(status));
377static bool incOrganizerOwnsCalendar(
const Calendar::Ptr &calendar,
384 return iamOrganizer(incidence);
387static QString displayViewFormatDescription(
const Incidence::Ptr &incidence)
390 if (!incidence->description().isEmpty()) {
392 if (!incidence->descriptionIsRich() &&
393 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
394 descStr = string2HTML(incidence->description());
396 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
397 descStr = incidence->richDescription();
399 descStr = incidence->description();
402 tmpStr += QLatin1String(
"<tr>");
403 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
404 tmpStr += QLatin1String(
"<td>") + descStr + QLatin1String(
"</td>");
405 tmpStr += QLatin1String(
"</tr>");
414 Attendee::List::ConstIterator it;
417 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
419 if (a->role() != role) {
423 if (attendeeIsOrganizer(incidence, a)) {
427 tmpStr += displayViewFormatPerson(a->email(), a->name(), a->uid(),
428 showStatus ? a->status() : Attendee::None);
429 if (!a->delegator().isEmpty()) {
430 tmpStr += i18n(
" (delegated by %1)", a->delegator());
432 if (!a->delegate().isEmpty()) {
433 tmpStr += i18n(
" (delegated to %1)", a->delegate());
435 tmpStr += QLatin1String(
"<br>");
437 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
448 int attendeeCount = incidence->attendees().count();
449 if (attendeeCount > 1 ||
450 (attendeeCount == 1 &&
451 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
453 QPair<QString, QString> s = searchNameAndUid(incidence->organizer()->email(),
454 incidence->organizer()->name(),
456 tmpStr += QLatin1String(
"<tr>");
457 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Organizer:") + QLatin1String(
"</b></td>");
458 const QString iconPath =
459 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
460 tmpStr += QLatin1String(
"<td>") + displayViewFormatPerson(incidence->organizer()->email(),
461 s.first, s.second, iconPath) +
462 QLatin1String(
"</td>");
463 tmpStr += QLatin1String(
"</tr>");
468 bool showStatus = incOrganizerOwnsCalendar(calendar, incidence);
471 str = displayViewFormatAttendeeRoleList(incidence,
Attendee::Chair, showStatus);
472 if (!str.isEmpty()) {
473 tmpStr += QLatin1String(
"<tr>");
474 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Chair:") + QLatin1String(
"</b></td>");
475 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
476 tmpStr += QLatin1String(
"</tr>");
481 if (!str.isEmpty()) {
482 tmpStr += QLatin1String(
"<tr>");
483 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Required Participants:") + QLatin1String(
"</b></td>");
484 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
485 tmpStr += QLatin1String(
"</tr>");
490 if (!str.isEmpty()) {
491 tmpStr += QLatin1String(
"<tr>");
492 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Optional Participants:") + QLatin1String(
"</b></td>");
493 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
494 tmpStr += QLatin1String(
"</tr>");
499 if (!str.isEmpty()) {
500 tmpStr += QLatin1String(
"<tr>");
501 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Observers:") + QLatin1String(
"</b></td>");
502 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
503 tmpStr += QLatin1String(
"</tr>");
509static QString displayViewFormatAttachments(
Incidence::Ptr incidence)
513 Attachment::List::ConstIterator it;
515 for (it = as.constBegin(); it != as.constEnd(); ++it) {
517 if ((*it)->isUri()) {
519 if ((*it)->uri().startsWith(QLatin1String(
"kmail:"))) {
520 name = i18n(
"Show mail");
522 if ((*it)->label().isEmpty()) {
525 name = (*it)->label();
528 tmpStr += htmlAddLink((*it)->uri(), name);
530 tmpStr += htmlAddLink(QString::fromLatin1(
"ATTACH:%1").
531 arg(QString::fromUtf8((*it)->label().toUtf8().toBase64())),
534 if (count < as.count()) {
535 tmpStr += QLatin1String(
"<br>");
541static QString displayViewFormatCategories(
Incidence::Ptr incidence)
544 return incidence->categories().join(QLatin1String(
", "));
547static QString displayViewFormatCreationDate(
Incidence::Ptr incidence, KDateTime::Spec spec)
549 KDateTime kdt = incidence->created().toTimeSpec(spec);
550 return i18n(
"Creation date: %1",
dateTimeToString(incidence->created(),
false,
true, spec));
553static QString displayViewFormatBirthday(
Event::Ptr event)
558 if (event->customProperty(
"KABC",
"BIRTHDAY") != QLatin1String(
"YES") &&
559 event->customProperty(
"KABC",
"ANNIVERSARY") != QLatin1String(
"YES")) {
563 const QString uid_1 =
event->customProperty(
"KABC",
"UID-1");
564 const QString name_1 =
event->customProperty(
"KABC",
"NAME-1");
565 const QString email_1=
event->customProperty(
"KABC",
"EMAIL-1");
569 const QString tmpStr = displayViewFormatPerson(p->email(), name_1, uid_1, QString());
575 QString tmpStr = QLatin1String(
"<table><tr>");
578 KIconLoader *iconLoader = KIconLoader::global();
579 tmpStr += QLatin1String(
"<td>");
582 if (incidence->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES")) {
583 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-birthday"), KIconLoader::Small);
584 }
else if (incidence->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES")) {
585 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-wedding-anniversary"), KIconLoader::Small);
587 iconPath = iconLoader->iconPath(incidence->iconName(), KIconLoader::Small);
589 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
591 if (incidence->hasEnabledAlarms()) {
592 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
593 iconLoader->iconPath(QLatin1String(
"preferences-desktop-notification-bell"), KIconLoader::Small) +
594 QLatin1String(
"\">");
596 if (incidence->recurs()) {
597 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
598 iconLoader->iconPath(QLatin1String(
"edit-redo"), KIconLoader::Small) +
599 QLatin1String(
"\">");
601 if (incidence->isReadOnly()) {
602 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
603 iconLoader->iconPath(QLatin1String(
"object-locked"), KIconLoader::Small) +
604 QLatin1String(
"\">");
606 tmpStr += QLatin1String(
"</td>");
608 tmpStr += QLatin1String(
"<td>");
609 tmpStr += QLatin1String(
"<b><u>") + incidence->richSummary() + QLatin1String(
"</u></b>");
610 tmpStr += QLatin1String(
"</td>");
612 tmpStr += QLatin1String(
"</tr></table>");
617static QString displayViewFormatEvent(
const Calendar::Ptr calendar,
const QString &sourceName,
619 const QDate &date, KDateTime::Spec spec)
625 QString tmpStr = displayViewFormatHeader(event);
627 tmpStr += QLatin1String(
"<table>");
628 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
629 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
631 const QString calStr = calendar ?
resourceString(calendar, event) : sourceName;
632 if (!calStr.isEmpty()) {
633 tmpStr += QLatin1String(
"<tr>");
634 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
635 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
636 tmpStr += QLatin1String(
"</tr>");
639 if (!event->location().isEmpty()) {
640 tmpStr += QLatin1String(
"<tr>");
641 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
642 tmpStr += QLatin1String(
"<td>") +
event->richLocation() + QLatin1String(
"</td>");
643 tmpStr +=QLatin1String(
"</tr>");
646 KDateTime startDt =
event->dtStart();
647 KDateTime endDt =
event->dtEnd();
648 if (event->recurs()) {
649 if (date.isValid()) {
650 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
651 int diffDays = startDt.daysTo(kdt);
652 kdt = kdt.addSecs(-1);
653 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
654 if (event->hasEndDate()) {
655 endDt = endDt.addDays(diffDays);
656 if (startDt > endDt) {
657 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
658 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
664 tmpStr += QLatin1String(
"<tr>");
665 if (event->allDay()) {
666 if (event->isMultiDay()) {
667 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
668 tmpStr += QLatin1String(
"<td>") +
669 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
672 QLatin1String(
"</td>");
674 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
675 tmpStr += QLatin1String(
"<td>") +
676 i18nc(
"date as string",
"%1",
678 QLatin1String(
"</td>");
681 if (event->isMultiDay()) {
682 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
683 tmpStr += QLatin1String(
"<td>") +
684 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
687 QLatin1String(
"</td>");
689 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
690 tmpStr += QLatin1String(
"<td>") +
691 i18nc(
"date as string",
"%1",
693 QLatin1String(
"</td>");
695 tmpStr += QLatin1String(
"</tr><tr>");
696 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Time:") + QLatin1String(
"</b></td>");
697 if (event->hasEndDate() && startDt != endDt) {
698 tmpStr += QLatin1String(
"<td>") +
699 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
702 QLatin1String(
"</td>");
704 tmpStr += QLatin1String(
"<td>") +
706 QLatin1String(
"</td>");
710 tmpStr += QLatin1String(
"</tr>");
713 if (!durStr.isEmpty()) {
714 tmpStr += QLatin1String(
"<tr>");
715 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
716 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
717 tmpStr += QLatin1String(
"</tr>");
720 if (event->recurs() || event->hasRecurrenceId()) {
721 tmpStr += QLatin1String(
"<tr>");
722 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
725 if (event->hasRecurrenceId()) {
726 str = i18n(
"Exception");
731 tmpStr += QLatin1String(
"<td>") + str +
732 QLatin1String(
"</td>");
733 tmpStr += QLatin1String(
"</tr>");
736 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES");
737 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES");
739 if (isBirthday || isAnniversary) {
740 tmpStr += QLatin1String(
"<tr>");
742 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Anniversary:") + QLatin1String(
"</b></td>");
744 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Birthday:") + QLatin1String(
"</b></td>");
746 tmpStr += QLatin1String(
"<td>") + displayViewFormatBirthday(event) + QLatin1String(
"</td>");
747 tmpStr += QLatin1String(
"</tr>");
748 tmpStr += QLatin1String(
"</table>");
752 tmpStr += displayViewFormatDescription(event);
756 int reminderCount =
event->alarms().count();
757 if (reminderCount > 0 && event->hasEnabledAlarms()) {
758 tmpStr += QLatin1String(
"<tr>");
759 tmpStr += QLatin1String(
"<td><b>") +
760 i18np(
"Reminder:",
"Reminders:", reminderCount) +
761 QLatin1String(
"</b></td>");
762 tmpStr += QLatin1String(
"<td>") +
reminderStringList(event).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
763 tmpStr += QLatin1String(
"</tr>");
766 tmpStr += displayViewFormatAttendees(calendar, event);
768 int categoryCount =
event->categories().count();
769 if (categoryCount > 0) {
770 tmpStr += QLatin1String(
"<tr>");
771 tmpStr += QLatin1String(
"<td><b>");
772 tmpStr += i18np(
"Category:",
"Categories:", categoryCount) +
773 QLatin1String(
"</b></td>");
774 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(event) + QLatin1String(
"</td>");
775 tmpStr += QLatin1String(
"</tr>");
778 int attachmentCount =
event->attachments().count();
779 if (attachmentCount > 0) {
780 tmpStr += QLatin1String(
"<tr>");
781 tmpStr += QLatin1String(
"<td><b>") +
782 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
783 QLatin1String(
"</b></td>");
784 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(event) + QLatin1String(
"</td>");
785 tmpStr += QLatin1String(
"</tr>");
787 tmpStr += QLatin1String(
"</table>");
789 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(event, spec) + QLatin1String(
"</em>");
794static QString displayViewFormatTodo(
const Calendar::Ptr &calendar,
const QString &sourceName,
796 const QDate &ocurrenceDueDate, KDateTime::Spec spec)
799 kDebug() <<
"IncidenceFormatter::displayViewFormatTodo was called without to-do, quitting";
803 QString tmpStr = displayViewFormatHeader(todo);
805 tmpStr += QLatin1String(
"<table>");
806 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
807 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
809 const QString calStr = calendar ?
resourceString(calendar, todo) : sourceName;
810 if (!calStr.isEmpty()) {
811 tmpStr += QLatin1String(
"<tr>");
812 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
813 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
814 tmpStr += QLatin1String(
"</tr>");
817 if (!todo->location().isEmpty()) {
818 tmpStr += QLatin1String(
"<tr>");
819 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
820 tmpStr += QLatin1String(
"<td>") + todo->richLocation() + QLatin1String(
"</td>");
821 tmpStr += QLatin1String(
"</tr>");
824 const bool hastStartDate = todo->hasStartDate();
825 const bool hasDueDate = todo->hasDueDate();
828 KDateTime startDt = todo->dtStart(
true );
829 if (todo->recurs() && ocurrenceDueDate.isValid()) {
832 const int length = startDt.daysTo(todo->dtDue(
true ));
834 startDt.setDate(ocurrenceDueDate.addDays(-length));
836 kError() <<
"DTSTART is bigger than DTDUE, todo->uid() is " << todo->uid();
837 startDt.setDate(ocurrenceDueDate);
840 kError() <<
"To-do is recurring but has no DTDUE set, todo->uid() is " << todo->uid();
841 startDt.setDate(ocurrenceDueDate);
844 tmpStr += QLatin1String(
"<tr>");
845 tmpStr += QLatin1String(
"<td><b>") +
846 i18nc(
"to-do start date/time",
"Start:") +
847 QLatin1String(
"</b></td>");
848 tmpStr += QLatin1String(
"<td>") +
850 QLatin1String(
"</td>");
851 tmpStr += QLatin1String(
"</tr>");
855 KDateTime dueDt = todo->dtDue();
856 if (todo->recurs()) {
857 if (ocurrenceDueDate.isValid()) {
858 KDateTime kdt(ocurrenceDueDate, QTime(0, 0, 0), KSystemTimeZones::local());
859 kdt = kdt.addSecs(-1);
860 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
863 tmpStr += QLatin1String(
"<tr>");
864 tmpStr += QLatin1String(
"<td><b>") +
865 i18nc(
"to-do due date/time",
"Due:") +
866 QLatin1String(
"</b></td>");
867 tmpStr += QLatin1String(
"<td>") +
869 QLatin1String(
"</td>");
870 tmpStr += QLatin1String(
"</tr>");
874 if (!durStr.isEmpty()) {
875 tmpStr += QLatin1String(
"<tr>");
876 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
877 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
878 tmpStr += QLatin1String(
"</tr>");
881 if (todo->recurs() || todo->hasRecurrenceId()) {
882 tmpStr += QLatin1String(
"<tr>");
883 tmpStr += QLatin1String(
"<td><b>")+ i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
885 if (todo->hasRecurrenceId()) {
886 str = i18n(
"Exception");
890 tmpStr += QLatin1String(
"<td>") +
892 QLatin1String(
"</td>");
893 tmpStr += QLatin1String(
"</tr>");
896 tmpStr += displayViewFormatDescription(todo);
900 int reminderCount = todo->alarms().count();
901 if (reminderCount > 0 && todo->hasEnabledAlarms()) {
902 tmpStr += QLatin1String(
"<tr>");
903 tmpStr += QLatin1String(
"<td><b>") +
904 i18np(
"Reminder:",
"Reminders:", reminderCount) +
905 QLatin1String(
"</b></td>");
906 tmpStr += QLatin1String(
"<td>") +
reminderStringList(todo).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
907 tmpStr += QLatin1String(
"</tr>");
910 tmpStr += displayViewFormatAttendees(calendar, todo);
912 int categoryCount = todo->categories().count();
913 if (categoryCount > 0) {
914 tmpStr += QLatin1String(
"<tr>");
915 tmpStr += QLatin1String(
"<td><b>") +
916 i18np(
"Category:",
"Categories:", categoryCount) +
917 QLatin1String(
"</b></td>");
918 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(todo) + QLatin1String(
"</td>");
919 tmpStr += QLatin1String(
"</tr>");
922 if (todo->priority() > 0) {
923 tmpStr += QLatin1String(
"<tr>");
924 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Priority:") + QLatin1String(
"</b></td>");
925 tmpStr += QLatin1String(
"<td>");
926 tmpStr += QString::number(todo->priority());
927 tmpStr += QLatin1String(
"</td>");
928 tmpStr += QLatin1String(
"</tr>");
931 tmpStr += QLatin1String(
"<tr>");
932 if (todo->isCompleted()) {
933 tmpStr += QLatin1String(
"<td><b>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</b></td>");
934 tmpStr += QLatin1String(
"<td>");
937 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Percent Done:") + QLatin1String(
"</b></td>");
938 tmpStr += QLatin1String(
"<td>");
939 tmpStr += i18n(
"%1%", todo->percentComplete());
941 tmpStr += QLatin1String(
"</td>");
942 tmpStr += QLatin1String(
"</tr>");
944 int attachmentCount = todo->attachments().count();
945 if (attachmentCount > 0) {
946 tmpStr += QLatin1String(
"<tr>");
947 tmpStr += QLatin1String(
"<td><b>") +
948 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
949 QLatin1String(
"</b></td>");
950 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(todo) + QLatin1String(
"</td>");
951 tmpStr += QLatin1String(
"</tr>");
953 tmpStr += QLatin1String(
"</table>");
955 tmpStr += QLatin1String(
"<p><em>")+ displayViewFormatCreationDate(todo, spec) + QLatin1String(
"</em>");
960static QString displayViewFormatJournal(
const Calendar::Ptr &calendar,
const QString &sourceName,
967 QString tmpStr = displayViewFormatHeader(journal);
969 tmpStr += QLatin1String(
"<table>");
970 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
971 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
973 const QString calStr = calendar ?
resourceString(calendar, journal) : sourceName;
974 if (!calStr.isEmpty()) {
975 tmpStr += QLatin1String(
"<tr>");
976 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
977 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
978 tmpStr += QLatin1String(
"</tr>");
981 tmpStr += QLatin1String(
"<tr>");
982 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
983 tmpStr += QLatin1String(
"<td>") +
985 QLatin1String(
"</td>");
986 tmpStr += QLatin1String(
"</tr>");
988 tmpStr += displayViewFormatDescription(journal);
990 int categoryCount = journal->categories().count();
991 if (categoryCount > 0) {
992 tmpStr += QLatin1String(
"<tr>");
993 tmpStr += QLatin1String(
"<td><b>") +
994 i18np(
"Category:",
"Categories:", categoryCount) +
995 QLatin1String(
"</b></td>");
996 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(journal) + QLatin1String(
"</td>");
997 tmpStr += QLatin1String(
"</tr>");
1000 tmpStr += QLatin1String(
"</table>");
1002 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(journal, spec) + QLatin1String(
"</em>");
1007static QString displayViewFormatFreeBusy(
const Calendar::Ptr &calendar,
const QString &sourceName,
1011 Q_UNUSED(sourceName);
1018 QLatin1String(
"h2"), i18n(
"Free/Busy information for %1", fb->organizer()->fullName())));
1020 tmpStr += htmlAddTag(QLatin1String(
"h4"),
1021 i18n(
"Busy times in date range %1 - %2:",
1026 htmlAddTag(QLatin1String(
"em"),
1027 htmlAddTag(QLatin1String(
"b"), i18nc(
"tag for busy periods list",
"Busy:")));
1030 Period::List::iterator it;
1031 for (it = periods.begin(); it != periods.end(); ++it) {
1037 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1041 cont += i18ncp(
"minutes part duration",
"1 minute ",
"%1 minutes ", dur / 60);
1045 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1047 text += i18nc(
"startDate for duration",
"%1 for %2",
1050 text += QLatin1String(
"<br>");
1052 if (per.
start().date() == per.
end().date()) {
1053 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1058 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1062 text += QLatin1String(
"<br>");
1065 tmpStr += htmlAddTag(QLatin1String(
"p"), text);
1071class KCalUtils::IncidenceFormatter::EventViewerVisitor :
public Visitor
1074 EventViewerVisitor()
1075 : mCalendar(0), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
1078 KDateTime::Spec spec=KDateTime::Spec())
1080 mCalendar = calendar;
1081 mSourceName.clear();
1084 mResult = QLatin1String(
"");
1085 return incidence->accept(*
this, incidence);
1089 KDateTime::Spec spec=KDateTime::Spec())
1091 mSourceName = sourceName;
1094 mResult = QLatin1String(
"");
1095 return incidence->accept(*
this, incidence);
1098 QString result()
const {
1105 mResult = displayViewFormatEvent(mCalendar, mSourceName, event, mDate, mSpec);
1106 return !mResult.isEmpty();
1110 mResult = displayViewFormatTodo(mCalendar, mSourceName, todo, mDate, mSpec);
1111 return !mResult.isEmpty();
1115 mResult = displayViewFormatJournal(mCalendar, mSourceName, journal, mSpec);
1116 return !mResult.isEmpty();
1120 mResult = displayViewFormatFreeBusy(mCalendar, mSourceName, fb, mSpec);
1121 return !mResult.isEmpty();
1126 QString mSourceName;
1128 KDateTime::Spec mSpec;
1136 KDateTime::Spec spec)
1142 EventViewerVisitor v;
1143 if (v.act(calendar, incidence, date, spec)) {
1153 KDateTime::Spec spec)
1159 EventViewerVisitor v;
1160 if (v.act(sourceName, incidence, date, spec)) {
1171static QString cleanHtml(
const QString &html)
1173 QRegExp rx(QLatin1String(
"<body[^>]*>(.*)</body>"), Qt::CaseInsensitive);
1175 QString body = rx.cap(1);
1177 return Qt::escape(body.remove(QRegExp(QLatin1String(
"<[^>]*>"))).trimmed());
1180static QString invitationSummary(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1182 QString summaryStr = i18n(
"Summary unspecified");
1183 if (!incidence->summary().isEmpty()) {
1184 if (!incidence->summaryIsRich()) {
1185 summaryStr = Qt::escape(incidence->summary());
1187 summaryStr = incidence->richSummary();
1189 summaryStr = cleanHtml(summaryStr);
1196static QString invitationLocation(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1198 QString locationStr = i18n(
"Location unspecified");
1199 if (!incidence->location().isEmpty()) {
1200 if (!incidence->locationIsRich()) {
1201 locationStr = Qt::escape(incidence->location());
1203 locationStr = incidence->richLocation();
1205 locationStr = cleanHtml(locationStr);
1212static QString eventStartTimeStr(
const Event::Ptr &event)
1215 if (!event->allDay()) {
1216 tmp = i18nc(
"%1: Start Date, %2: Start Time",
"%1 %2",
1217 dateToString(event->dtStart(),
true, KSystemTimeZones::local()),
1218 timeToString(event->dtStart(),
true, KSystemTimeZones::local()));
1220 tmp = i18nc(
"%1: Start Date",
"%1 (all day)",
1221 dateToString(event->dtStart(),
true, KSystemTimeZones::local()));
1226static QString eventEndTimeStr(
const Event::Ptr &event)
1229 if (event->hasEndDate() && event->dtEnd().isValid()) {
1230 if (!event->allDay()) {
1231 tmp = i18nc(
"%1: End Date, %2: End Time",
"%1 %2",
1232 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()),
1233 timeToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1235 tmp = i18nc(
"%1: End Date",
"%1 (all day)",
1236 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1242static QString htmlInvitationDetailsBegin()
1244 QString dir = (QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr"));
1245 return QString::fromLatin1(
"<div dir=\"%1\">\n").arg(dir);
1248static QString htmlInvitationDetailsEnd()
1250 return QLatin1String(
"</div>\n");
1253static QString htmlInvitationDetailsTableBegin()
1255 return QLatin1String(
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">");
1258static QString htmlInvitationDetailsTableEnd()
1260 return QLatin1String(
"</table>\n");
1263static QString diffColor()
1268 return QColor(Qt::red).name();
1271static QString noteColor()
1274 return qApp->palette().color(QPalette::Active, QPalette::Highlight).name();
1277static QString htmlRow(
const QString &title,
const QString &value)
1279 if (!value.isEmpty()) {
1280 return QLatin1String(
"<tr><td>") + title + QLatin1String(
"</td><td>") + value + QLatin1String(
"</td></tr>\n");
1286static QString htmlRow(
const QString &title,
const QString &value,
const QString &oldvalue)
1289 if (value.isEmpty()) {
1294 if (oldvalue.isEmpty() || value == oldvalue) {
1295 return htmlRow(title, value);
1299 QString color = diffColor();
1300 QString newtitle = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + title + QLatin1String(
"</font>");
1301 QString newvalue = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + value + QLatin1String(
"</font>") +
1302 QLatin1String(
" ")+
1303 QLatin1String(
"(<strike>") + oldvalue + QLatin1String(
"</strike>");
1304 return htmlRow(newtitle, newvalue);
1316 RAIIIdentityManager raiiHelper;
1317 QString delegatorName, delegatorEmail;
1319 Attendee::List::ConstIterator it;
1320 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1322 KPIMUtils::extractEmailAddressAndName(a->delegator(), delegatorEmail, delegatorName);
1323 if (thatIsMe(delegatorEmail)) {
1341 RAIIIdentityManager raiiHelper;
1343 Attendee::List::ConstIterator it;
1344 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1346 if (thatIsMe(a->email())) {
1356 const QString &email)
1365 RAIIIdentityManager raiiHelper;
1367 Attendee::List::ConstIterator it;
1368 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1370 if (email == a->email()) {
1388 Attendee::List::ConstIterator it;
1389 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1390 if (it == attendees.constBegin()) {
1391 rsvp = (*it)->RSVP();
1393 if ((*it)->RSVP() != rsvp) {
1402static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role)
1404 if (rsvpRequested) {
1405 if (role.isEmpty()) {
1406 return i18n(
"Your response is requested");
1408 return i18n(
"Your response as <b>%1</b> is requested", role);
1411 if (role.isEmpty()) {
1412 return i18n(
"No response is necessary");
1414 return i18n(
"No response as <b>%1</b> is necessary", role);
1425 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1426 Stringify::attendeeStatus(a->status()));
1431static QString invitationNote(
const QString &title,
const QString ¬e,
1432 const QString &tag,
const QString &color)
1435 if (!note.isEmpty()) {
1436 noteStr += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1437 noteStr += QLatin1String(
"<tr><center><td>");
1438 if (!color.isEmpty()) {
1439 noteStr += QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">");
1441 if (!title.isEmpty()) {
1442 if (!tag.isEmpty()) {
1443 noteStr += htmlAddTag(tag, title);
1448 noteStr += QLatin1String(
" )") + note;
1449 if (!color.isEmpty()) {
1450 noteStr += QLatin1String(
"</font>");
1452 noteStr += QLatin1String(
"</td></center></tr>");
1453 noteStr += QLatin1String(
"</table>");
1458static QString invitationPerson(
const QString &email,
const QString &name,
const QString &uid,
1459 const QString &comment)
1461 QPair<QString, QString> s = searchNameAndUid(email, name, uid);
1462 const QString printName = s.first;
1463 const QString printUid = s.second;
1465 QString personString;
1467 if (!printUid.isEmpty()) {
1468 personString = htmlAddUidLink(email, printName, printUid);
1471 personString = (printName.isEmpty() ? email : printName);
1473 if (!comment.isEmpty()) {
1474 personString = i18nc(
"name (comment)",
"%1 (%2)", personString, comment);
1476 personString += QLatin1Char(
'\n');
1479 if (!email.isEmpty()) {
1480 personString += QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
1482 personString += QLatin1Char(
'\n');
1484 return personString;
1487static QString invitationDetailsIncidence(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1495 QStringList comments;
1497 if (incidence->comments().isEmpty()) {
1498 if (!incidence->description().isEmpty()) {
1500 if (!incidence->descriptionIsRich() &&
1501 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1502 comments << string2HTML(incidence->description());
1504 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1505 comments << incidence->richDescription();
1507 comments << incidence->description();
1510 comments[0] = cleanHtml(comments[0]);
1512 comments[0] = htmlAddTag(QLatin1String(
"p"), comments[0]);
1518 foreach (
const QString &c, incidence->comments()) {
1521 if (!Qt::mightBeRichText(c)) {
1522 comments << string2HTML(c);
1525 comments << cleanHtml(cleanHtml(QLatin1String(
"<body>") + c +QLatin1String(
"</body>")));
1532 if (!incidence->description().isEmpty()) {
1534 if (!incidence->descriptionIsRich() &&
1535 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1536 descr = string2HTML(incidence->description());
1538 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1539 descr = incidence->richDescription();
1541 descr = incidence->description();
1544 descr = cleanHtml(descr);
1546 descr = htmlAddTag(QLatin1String(
"p"), descr);
1551 if (!descr.isEmpty()) {
1552 html += QLatin1String(
"<p>");
1553 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1554 html += QLatin1String(
"<tr><td><center>") +
1555 htmlAddTag(QLatin1String(
"u"), i18n(
"Description:")) +
1556 QLatin1String(
"</center></td></tr>");
1557 html += QLatin1String(
"<tr><td>") + descr + QLatin1String(
"</td></tr>");
1558 html += QLatin1String(
"</table>");
1561 if (!comments.isEmpty()) {
1562 html += QLatin1String(
"<p>");
1563 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1564 html += QLatin1String(
"<tr><td><center>") +
1565 htmlAddTag(QLatin1String(
"u"), i18n(
"Comments:")) +
1566 QLatin1String(
"</center></td></tr>");
1567 html += QLatin1String(
"<tr><td>");
1568 if (comments.count() > 1) {
1569 html += QLatin1String(
"<ul>");
1570 for (
int i=0; i < comments.count(); ++i) {
1571 html += QLatin1String(
"<li>") + comments[i] + QLatin1String(
"</li>");
1573 html += QLatin1String(
"</ul>");
1575 html += comments[0];
1577 html += QLatin1String(
"</td></tr>");
1578 html += QLatin1String(
"</table>");
1583static QString invitationDetailsEvent(
const Event::Ptr &event,
bool noHtmlMode,
1584 KDateTime::Spec spec)
1591 QString html = htmlInvitationDetailsBegin();
1592 html += htmlInvitationDetailsTableBegin();
1595 html += htmlRow(i18n(
"What:"), invitationSummary(event, noHtmlMode));
1596 html += htmlRow(i18n(
"Where:"), invitationLocation(event, noHtmlMode));
1599 if (event->dtStart().date() == event->dtEnd().date()) {
1600 html += htmlRow(i18n(
"Date:"),
dateToString(event->dtStart(),
false, spec));
1601 if (!event->allDay()) {
1602 html += htmlRow(i18n(
"Time:"),
1604 QLatin1String(
" - ") +
1608 html += htmlRow(i18nc(
"starting date",
"From:"),
1610 if (!event->allDay()) {
1611 html += htmlRow(i18nc(
"starting time",
"At:"),
1614 if (event->hasEndDate()) {
1615 html += htmlRow(i18nc(
"ending date",
"To:"),
1617 if (!event->allDay()) {
1618 html += htmlRow(i18nc(
"ending time",
"At:"),
1622 html += htmlRow(i18nc(
"ending date",
"To:"), i18n(
"no end date specified"));
1630 if (event->recurs()) {
1634 html += htmlInvitationDetailsTableEnd();
1635 html += invitationDetailsIncidence(event, noHtmlMode);
1636 html += htmlInvitationDetailsEnd();
1643 KDateTime::Spec spec)
1646 return invitationDetailsEvent(event, noHtmlMode, spec);
1652 if (message->method() == iTIPDeclineCounter) {
1653 html += QLatin1String(
"<br>");
1654 html += invitationNote(QString(),
1655 i18n(
"Please respond again to the original proposal."),
1656 QString(), noteColor());
1659 html += htmlInvitationDetailsBegin();
1660 html += htmlInvitationDetailsTableBegin();
1662 html += htmlRow(i18n(
"What:"),
1663 invitationSummary(event, noHtmlMode),
1664 invitationSummary(oldevent, noHtmlMode));
1666 html += htmlRow(i18n(
"Where:"),
1667 invitationLocation(event, noHtmlMode),
1668 invitationLocation(oldevent, noHtmlMode));
1671 if (event->dtStart().date() == event->dtEnd().date()) {
1672 html += htmlRow(i18n(
"Date:"),
1675 QString spanStr, oldspanStr;
1676 if (!event->allDay()) {
1678 QLatin1String(
" - ") +
1681 if (!oldevent->allDay()) {
1682 oldspanStr =
timeToString(oldevent->dtStart(),
true, spec) +
1683 QLatin1String(
" - ") +
1686 html += htmlRow(i18n(
"Time:"), spanStr, oldspanStr);
1688 html += htmlRow(i18nc(
"Starting date of an event",
"From:"),
1691 QString startStr, oldstartStr;
1692 if (!event->allDay()) {
1695 if (!oldevent->allDay()) {
1696 oldstartStr =
timeToString(oldevent->dtStart(),
true, spec);
1698 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), startStr, oldstartStr);
1699 if (event->hasEndDate()) {
1700 html += htmlRow(i18nc(
"Ending date of an event",
"To:"),
1703 QString endStr, oldendStr;
1704 if (!event->allDay()) {
1707 if (!oldevent->allDay()) {
1708 oldendStr =
timeToString(oldevent->dtEnd(),
true, spec);
1710 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), endStr, oldendStr);
1712 QString endStr = i18n(
"no end date specified");
1714 if (!oldevent->hasEndDate()) {
1715 oldendStr = i18n(
"no end date specified");
1717 oldendStr =
dateTimeToString(oldevent->dtEnd(), oldevent->allDay(),
false);
1719 html += htmlRow(i18nc(
"Ending date of an event",
"To:"), endStr, oldendStr);
1725 QString recurStr, oldrecurStr;
1726 if (event->recurs() || oldevent->recurs()) {
1730 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1732 html += htmlInvitationDetailsTableEnd();
1733 html += invitationDetailsIncidence(event, noHtmlMode);
1734 html += htmlInvitationDetailsEnd();
1739static QString invitationDetailsTodo(
const Todo::Ptr &todo,
bool noHtmlMode,
1740 KDateTime::Spec spec)
1747 QString html = htmlInvitationDetailsBegin();
1748 html += htmlInvitationDetailsTableBegin();
1751 html += htmlRow(i18n(
"What:"), invitationSummary(todo, noHtmlMode));
1752 html += htmlRow(i18n(
"Where:"), invitationLocation(todo, noHtmlMode));
1754 if (todo->hasStartDate()) {
1755 html += htmlRow(i18n(
"Start Date:"),
dateToString(todo->dtStart(),
false, spec));
1756 if (!todo->allDay()) {
1757 html += htmlRow(i18n(
"Start Time:"),
timeToString(todo->dtStart(),
false, spec));
1760 if (todo->hasDueDate()) {
1761 html += htmlRow(i18n(
"Due Date:"),
dateToString(todo->dtDue(),
false, spec));
1762 if (!todo->allDay()) {
1763 html += htmlRow(i18n(
"Due Time:"),
timeToString(todo->dtDue(),
false, spec));
1766 html += htmlRow(i18n(
"Due Date:"), i18nc(
"Due Date: None",
"None"));
1773 if (todo->percentComplete() > 0) {
1774 html += htmlRow(i18n(
"Percent Done:"), i18n(
"%1%", todo->percentComplete()));
1778 if (todo->recurs()) {
1782 html += htmlInvitationDetailsTableEnd();
1783 html += invitationDetailsIncidence(todo, noHtmlMode);
1784 html += htmlInvitationDetailsEnd();
1791 KDateTime::Spec spec)
1794 return invitationDetailsTodo(todo, noHtmlMode, spec);
1800 if (message->method() == iTIPDeclineCounter) {
1801 html += QLatin1String(
"<br>");
1802 html += invitationNote(QString(),
1803 i18n(
"Please respond again to the original proposal."),
1804 QString(), noteColor());
1807 html += htmlInvitationDetailsBegin();
1808 html += htmlInvitationDetailsTableBegin();
1810 html += htmlRow(i18n(
"What:"),
1811 invitationSummary(todo, noHtmlMode),
1812 invitationSummary(todo, noHtmlMode));
1814 html += htmlRow(i18n(
"Where:"),
1815 invitationLocation(todo, noHtmlMode),
1816 invitationLocation(oldtodo, noHtmlMode));
1818 if (todo->hasStartDate()) {
1819 html += htmlRow(i18n(
"Start Date:"),
1822 QString startTimeStr, oldstartTimeStr;
1823 if (!todo->allDay() || !oldtodo->allDay()) {
1824 startTimeStr = todo->allDay() ?
1825 i18n(
"All day") :
timeToString(todo->dtStart(), false, spec);
1826 oldstartTimeStr = oldtodo->allDay() ?
1827 i18n(
"All day") :
timeToString(oldtodo->dtStart(), false, spec);
1829 html += htmlRow(i18n(
"Start Time:"), startTimeStr, oldstartTimeStr);
1831 if (todo->hasDueDate()) {
1832 html += htmlRow(i18n(
"Due Date:"),
1835 QString endTimeStr, oldendTimeStr;
1836 if (!todo->allDay() || !oldtodo->allDay()) {
1837 endTimeStr = todo->allDay() ?
1838 i18n(
"All day") :
timeToString(todo->dtDue(), false, spec);
1839 oldendTimeStr = oldtodo->allDay() ?
1840 i18n(
"All day") :
timeToString(oldtodo->dtDue(), false, spec);
1842 html += htmlRow(i18n(
"Due Time:"), endTimeStr, oldendTimeStr);
1844 QString dueStr = i18nc(
"Due Date: None",
"None");
1846 if (!oldtodo->hasDueDate()) {
1847 olddueStr = i18nc(
"Due Date: None",
"None");
1851 html += htmlRow(i18n(
"Due Date:"), dueStr, olddueStr);
1856 QString completionStr, oldcompletionStr;
1857 if (todo->percentComplete() > 0 || oldtodo->percentComplete() > 0) {
1858 completionStr = i18n(
"%1%", todo->percentComplete());
1859 oldcompletionStr = i18n(
"%1%", oldtodo->percentComplete());
1861 html += htmlRow(i18n(
"Percent Done:"), completionStr, oldcompletionStr);
1863 QString recurStr, oldrecurStr;
1864 if (todo->recurs() || oldtodo->recurs()) {
1868 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1870 html += htmlInvitationDetailsTableEnd();
1871 html += invitationDetailsIncidence(todo, noHtmlMode);
1873 html += htmlInvitationDetailsEnd();
1878static QString invitationDetailsJournal(
const Journal::Ptr &journal,
bool noHtmlMode,
1879 KDateTime::Spec spec)
1885 QString html = htmlInvitationDetailsBegin();
1886 html += htmlInvitationDetailsTableBegin();
1888 html += htmlRow(i18n(
"Summary:"), invitationSummary(journal, noHtmlMode));
1889 html += htmlRow(i18n(
"Date:"),
dateToString(journal->dtStart(),
false, spec));
1891 html += htmlInvitationDetailsTableEnd();
1892 html += invitationDetailsIncidence(journal, noHtmlMode);
1893 html += htmlInvitationDetailsEnd();
1898static QString invitationDetailsJournal(
const Journal::Ptr &journal,
1900 bool noHtmlMode, KDateTime::Spec spec)
1903 return invitationDetailsJournal(journal, noHtmlMode, spec);
1906 QString html = htmlInvitationDetailsBegin();
1907 html += htmlInvitationDetailsTableBegin();
1909 html += htmlRow(i18n(
"What:"),
1910 invitationSummary(journal, noHtmlMode),
1911 invitationSummary(oldjournal, noHtmlMode));
1913 html += htmlRow(i18n(
"Date:"),
1917 html += htmlInvitationDetailsTableEnd();
1918 html += invitationDetailsIncidence(journal, noHtmlMode);
1919 html += htmlInvitationDetailsEnd();
1924static QString invitationDetailsFreeBusy(
const FreeBusy::Ptr &fb,
bool noHtmlMode,
1925 KDateTime::Spec spec)
1927 Q_UNUSED(noHtmlMode);
1933 QString html = htmlInvitationDetailsTableBegin();
1935 html += htmlRow(i18n(
"Person:"), fb->organizer()->fullName());
1936 html += htmlRow(i18n(
"Start date:"),
dateToString(fb->dtStart(),
true, spec));
1937 html += htmlRow(i18n(
"End date:"),
dateToString(fb->dtEnd(),
true, spec));
1939 html += QLatin1String(
"<tr><td colspan=2><hr></td></tr>\n");
1940 html += QLatin1String(
"<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n");
1943 Period::List::iterator it;
1944 for (it = periods.begin(); it != periods.end(); ++it) {
1950 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1954 cont += i18ncp(
"minutes part of duration",
"1 minute",
"%1 minutes ", dur / 60);
1958 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1960 html += htmlRow(QString(),
1961 i18nc(
"startDate for duration",
"%1 for %2",
1963 per.
start().dateTime(), KLocale::LongDate),
1967 if (per.
start().date() == per.
end().date()) {
1968 cont = i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1970 KGlobal::locale()->formatTime(per.
start().time()),
1971 KGlobal::locale()->formatTime(per.
end().time()));
1973 cont = i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1975 per.
start().dateTime(), KLocale::LongDate),
1976 KGlobal::locale()->formatDateTime(
1977 per.
end().dateTime(), KLocale::LongDate));
1980 html += htmlRow(QString(), cont);
1984 html += htmlInvitationDetailsTableEnd();
1989 bool noHtmlMode, KDateTime::Spec spec)
1992 return invitationDetailsFreeBusy(fb, noHtmlMode, spec);
1997 Q_UNUSED(incidence);
2015static QString invitationHeaderEvent(
const Event::Ptr &event,
2019 if (!msg || !event) {
2023 switch (msg->method()) {
2025 return i18n(
"This invitation has been published");
2027 if (existingIncidence && event->revision() > 0) {
2028 QString orgStr = organizerName(event, sender);
2029 if (senderIsOrganizer(event, sender)) {
2030 return i18n(
"This invitation has been updated by the organizer %1", orgStr);
2032 return i18n(
"This invitation has been updated by %1 as a representative of %2",
2036 if (iamOrganizer(event)) {
2037 return i18n(
"I created this invitation");
2039 QString orgStr = organizerName(event, sender);
2040 if (senderIsOrganizer(event, sender)) {
2041 return i18n(
"You received an invitation from %1", orgStr);
2043 return i18n(
"You received an invitation from %1 as a representative of %2",
2048 return i18n(
"This invitation was refreshed");
2050 if (iamOrganizer(event)) {
2051 return i18n(
"This invitation has been canceled");
2053 return i18n(
"The organizer has revoked the invitation");
2056 return i18n(
"Addition to the invitation");
2059 if (replyMeansCounter(event)) {
2060 return i18n(
"%1 makes this counter proposal", firstAttendeeName(event, sender));
2064 if (attendees.count() == 0) {
2065 kDebug() <<
"No attendees in the iCal reply!";
2068 if (attendees.count() != 1) {
2069 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2070 <<
"but is" << attendees.count();
2072 QString attendeeName = firstAttendeeName(event, sender);
2074 QString delegatorName, dummy;
2076 KPIMUtils::extractEmailAddressAndName(attendee->delegator(), dummy, delegatorName);
2077 if (delegatorName.isEmpty()) {
2078 delegatorName = attendee->delegator();
2081 switch (attendee->status()) {
2083 return i18n(
"%1 indicates this invitation still needs some action", attendeeName);
2085 if (event->revision() > 0) {
2086 if (!sender.isEmpty()) {
2087 return i18n(
"This invitation has been updated by attendee %1", sender);
2089 return i18n(
"This invitation has been updated by an attendee");
2092 if (delegatorName.isEmpty()) {
2093 return i18n(
"%1 accepts this invitation", attendeeName);
2095 return i18n(
"%1 accepts this invitation on behalf of %2",
2096 attendeeName, delegatorName);
2100 if (delegatorName.isEmpty()) {
2101 return i18n(
"%1 tentatively accepts this invitation", attendeeName);
2103 return i18n(
"%1 tentatively accepts this invitation on behalf of %2",
2104 attendeeName, delegatorName);
2107 if (delegatorName.isEmpty()) {
2108 return i18n(
"%1 declines this invitation", attendeeName);
2110 return i18n(
"%1 declines this invitation on behalf of %2",
2111 attendeeName, delegatorName);
2115 QString delegate, dummy;
2116 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2117 if (delegate.isEmpty()) {
2118 delegate = attendee->delegate();
2120 if (!delegate.isEmpty()) {
2121 return i18n(
"%1 has delegated this invitation to %2", attendeeName, delegate);
2123 return i18n(
"%1 has delegated this invitation", attendeeName);
2127 return i18n(
"This invitation is now completed");
2129 return i18n(
"%1 is still processing the invitation", attendeeName);
2130 case Attendee::None:
2131 return i18n(
"Unknown response to this invitation");
2136 return i18n(
"%1 makes this counter proposal",
2137 firstAttendeeName(event, i18n(
"Sender")));
2141 QString orgStr = organizerName(event, sender);
2142 if (senderIsOrganizer(event, sender)) {
2143 return i18n(
"%1 declines your counter proposal", orgStr);
2145 return i18n(
"%1 declines your counter proposal on behalf of %2", sender, orgStr);
2150 return i18n(
"Error: Event iTIP message with unknown method");
2152 kError() <<
"encountered an iTIP method that we do not support";
2156static QString invitationHeaderTodo(
const Todo::Ptr &todo,
2160 if (!msg || !todo) {
2164 switch (msg->method()) {
2166 return i18n(
"This to-do has been published");
2168 if (existingIncidence && todo->revision() > 0) {
2169 QString orgStr = organizerName(todo, sender);
2170 if (senderIsOrganizer(todo, sender)) {
2171 return i18n(
"This to-do has been updated by the organizer %1", orgStr);
2173 return i18n(
"This to-do has been updated by %1 as a representative of %2",
2177 if (iamOrganizer(todo)) {
2178 return i18n(
"I created this to-do");
2180 QString orgStr = organizerName(todo, sender);
2181 if (senderIsOrganizer(todo, sender)) {
2182 return i18n(
"You have been assigned this to-do by %1", orgStr);
2184 return i18n(
"You have been assigned this to-do by %1 as a representative of %2",
2190 return i18n(
"This to-do was refreshed");
2192 if (iamOrganizer(todo)) {
2193 return i18n(
"This to-do was canceled");
2195 return i18n(
"The organizer has revoked this to-do");
2198 return i18n(
"Addition to the to-do");
2201 if (replyMeansCounter(todo)) {
2202 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2206 if (attendees.count() == 0) {
2207 kDebug() <<
"No attendees in the iCal reply!";
2210 if (attendees.count() != 1) {
2211 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2212 <<
"but is" << attendees.count();
2214 QString attendeeName = firstAttendeeName(todo, sender);
2216 QString delegatorName, dummy;
2218 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegatorName);
2219 if (delegatorName.isEmpty()) {
2220 delegatorName = attendee->delegator();
2223 switch (attendee->status()) {
2225 return i18n(
"%1 indicates this to-do assignment still needs some action",
2228 if (todo->revision() > 0) {
2229 if (!sender.isEmpty()) {
2230 if (todo->isCompleted()) {
2231 return i18n(
"This to-do has been completed by assignee %1", sender);
2233 return i18n(
"This to-do has been updated by assignee %1", sender);
2236 if (todo->isCompleted()) {
2237 return i18n(
"This to-do has been completed by an assignee");
2239 return i18n(
"This to-do has been updated by an assignee");
2243 if (delegatorName.isEmpty()) {
2244 return i18n(
"%1 accepts this to-do", attendeeName);
2246 return i18n(
"%1 accepts this to-do on behalf of %2",
2247 attendeeName, delegatorName);
2251 if (delegatorName.isEmpty()) {
2252 return i18n(
"%1 tentatively accepts this to-do", attendeeName);
2254 return i18n(
"%1 tentatively accepts this to-do on behalf of %2",
2255 attendeeName, delegatorName);
2258 if (delegatorName.isEmpty()) {
2259 return i18n(
"%1 declines this to-do", attendeeName);
2261 return i18n(
"%1 declines this to-do on behalf of %2",
2262 attendeeName, delegatorName);
2266 QString delegate, dummy;
2267 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2268 if (delegate.isEmpty()) {
2269 delegate = attendee->delegate();
2271 if (!delegate.isEmpty()) {
2272 return i18n(
"%1 has delegated this to-do to %2", attendeeName, delegate);
2274 return i18n(
"%1 has delegated this to-do", attendeeName);
2278 return i18n(
"The request for this to-do is now completed");
2280 return i18n(
"%1 is still processing the to-do", attendeeName);
2281 case Attendee::None:
2282 return i18n(
"Unknown response to this to-do");
2287 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2291 QString orgStr = organizerName(todo, sender);
2292 if (senderIsOrganizer(todo, sender)) {
2293 return i18n(
"%1 declines the counter proposal", orgStr);
2295 return i18n(
"%1 declines the counter proposal on behalf of %2", sender, orgStr);
2300 return i18n(
"Error: To-do iTIP message with unknown method");
2302 kError() <<
"encountered an iTIP method that we do not support";
2306static QString invitationHeaderJournal(
const Journal::Ptr &journal,
2309 if (!msg || !journal) {
2313 switch (msg->method()) {
2315 return i18n(
"This journal has been published");
2317 return i18n(
"You have been assigned this journal");
2319 return i18n(
"This journal was refreshed");
2321 return i18n(
"This journal was canceled");
2323 return i18n(
"Addition to the journal");
2326 if (replyMeansCounter(journal)) {
2327 return i18n(
"Sender makes this counter proposal");
2331 if (attendees.count() == 0) {
2332 kDebug() <<
"No attendees in the iCal reply!";
2335 if (attendees.count() != 1) {
2336 kDebug() <<
"Warning: attendeecount in the reply should be 1 "
2337 <<
"but is " << attendees.count();
2341 switch (attendee->status()) {
2343 return i18n(
"Sender indicates this journal assignment still needs some action");
2345 return i18n(
"Sender accepts this journal");
2347 return i18n(
"Sender tentatively accepts this journal");
2349 return i18n(
"Sender declines this journal");
2351 return i18n(
"Sender has delegated this request for the journal");
2353 return i18n(
"The request for this journal is now completed");
2355 return i18n(
"Sender is still processing the invitation");
2356 case Attendee::None:
2357 return i18n(
"Unknown response to this journal");
2362 return i18n(
"Sender makes this counter proposal");
2364 return i18n(
"Sender declines the counter proposal");
2366 return i18n(
"Error: Journal iTIP message with unknown method");
2368 kError() <<
"encountered an iTIP method that we do not support";
2372static QString invitationHeaderFreeBusy(
const FreeBusy::Ptr &fb,
2379 switch (msg->method()) {
2381 return i18n(
"This free/busy list has been published");
2383 return i18n(
"The free/busy list has been requested");
2385 return i18n(
"This free/busy list was refreshed");
2387 return i18n(
"This free/busy list was canceled");
2389 return i18n(
"Addition to the free/busy list");
2391 return i18n(
"Reply to the free/busy list");
2393 return i18n(
"Sender makes this counter proposal");
2395 return i18n(
"Sender declines the counter proposal");
2397 return i18n(
"Error: Free/Busy iTIP message with unknown method");
2399 kError() <<
"encountered an iTIP method that we do not support";
2404static QString invitationAttendeeList(
const Incidence::Ptr &incidence)
2406 RAIIIdentityManager raiiHelper;
2412 if (incidence->type() == Incidence::TypeTodo) {
2413 tmpStr += i18n(
"Assignees");
2415 tmpStr += i18n(
"Invitation List");
2420 if (!attendees.isEmpty()) {
2421 QStringList comments;
2422 Attendee::List::ConstIterator it;
2423 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2425 if (!iamAttendee(a)) {
2428 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2430 tmpStr += QLatin1String(
"<tr>");
2431 tmpStr += QLatin1String(
"<td>");
2433 if (attendeeIsOrganizer(incidence, a)) {
2434 comments << i18n(
"organizer");
2436 if (!a->delegator().isEmpty()) {
2437 comments << i18n(
" (delegated by %1)", a->delegator());
2439 if (!a->delegate().isEmpty()) {
2440 comments << i18n(
" (delegated to %1)", a->delegate());
2442 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2443 tmpStr += QLatin1String(
"</td>");
2444 tmpStr += QLatin1String(
"</tr>");
2449 tmpStr += QLatin1String(
"</table>");
2463 if (incidence->type() == Incidence::TypeTodo) {
2464 tmpStr += i18n(
"Assignees");
2466 tmpStr += i18n(
"Invitation List");
2471 if (!attendees.isEmpty()) {
2472 QStringList comments;
2473 Attendee::List::ConstIterator it;
2474 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2476 if (!attendeeIsOrganizer(incidence, a)) {
2477 QString statusStr = Stringify::attendeeStatus(a->status());
2478 if (sender && (a->email() == sender->email())) {
2481 if (a->status() != sender->status()) {
2482 statusStr = i18n(
"%1 (<i>unrecorded</i>)",
2483 Stringify::attendeeStatus(sender->status()));
2489 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2491 tmpStr += QLatin1String(
"<tr>");
2492 tmpStr += QLatin1String(
"<td>");
2494 if (iamAttendee(a)) {
2495 comments << i18n(
"myself");
2497 if (!a->delegator().isEmpty()) {
2498 comments << i18n(
" (delegated by %1)", a->delegator());
2500 if (!a->delegate().isEmpty()) {
2501 comments << i18n(
" (delegated to %1)", a->delegate());
2503 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2504 tmpStr += QLatin1String(
"</td>");
2505 tmpStr += QLatin1String(
"<td>")+ statusStr + QLatin1String(
"</td>");
2506 tmpStr += QLatin1String(
"</tr>");
2511 tmpStr += QLatin1String(
"</table>");
2513 tmpStr += QLatin1String(
"<i> ") + i18nc(
"no attendees",
"None") + QLatin1String(
"</i>");
2519static QString invitationAttachments(InvitationFormatterHelper *helper,
2527 if (incidence->type() == Incidence::TypeFreeBusy) {
2533 if (!attachments.isEmpty()) {
2534 tmpStr += i18n(
"Attached Documents:") + QLatin1String(
"<ol>");
2536 Attachment::List::ConstIterator it;
2537 for (it = attachments.constBegin(); it != attachments.constEnd(); ++it) {
2539 tmpStr += QLatin1String(
"<li>");
2541 KMimeType::Ptr
mimeType = KMimeType::mimeType(a->mimeType());
2542 const QString iconStr = (
mimeType ?
2544 QLatin1String(
"application-octet-stream"));
2545 const QString iconPath = KIconLoader::global()->iconPath(iconStr, KIconLoader::Small);
2546 if (!iconPath.isEmpty()) {
2547 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
2549 tmpStr += helper->makeLink(QLatin1String(
"ATTACH:") + QLatin1String(a->label().toUtf8().toBase64()), a->label());
2550 tmpStr += QLatin1String(
"</li>");
2552 tmpStr += QLatin1String(
"</ol>");
2559class KCalUtils::IncidenceFormatter::ScheduleMessageVisitor :
public Visitor
2562 ScheduleMessageVisitor() : mMessage(0) {
2563 mResult = QLatin1String(
"");
2569 mExistingIncidence = existingIncidence;
2572 return incidence->accept(*
this, incidence);
2574 QString result()
const {
2585class KCalUtils::IncidenceFormatter::InvitationHeaderVisitor :
2586 public IncidenceFormatter::ScheduleMessageVisitor
2591 mResult = invitationHeaderEvent(event, mExistingIncidence, mMessage, mSender);
2592 return !mResult.isEmpty();
2596 mResult = invitationHeaderTodo(todo, mExistingIncidence, mMessage, mSender);
2597 return !mResult.isEmpty();
2601 mResult = invitationHeaderJournal(journal, mMessage);
2602 return !mResult.isEmpty();
2606 mResult = invitationHeaderFreeBusy(fb, mMessage);
2607 return !mResult.isEmpty();
2611class KCalUtils::IncidenceFormatter::InvitationBodyVisitor
2612 :
public IncidenceFormatter::ScheduleMessageVisitor
2615 InvitationBodyVisitor(
bool noHtmlMode, KDateTime::Spec spec)
2616 : ScheduleMessageVisitor(), mNoHtmlMode(noHtmlMode), mSpec(spec) {}
2622 mResult = invitationDetailsEvent(event, oldevent, mMessage, mNoHtmlMode, mSpec);
2623 return !mResult.isEmpty();
2628 mResult = invitationDetailsTodo(todo, oldtodo, mMessage, mNoHtmlMode, mSpec);
2629 return !mResult.isEmpty();
2634 mResult = invitationDetailsJournal(journal, oldjournal, mNoHtmlMode, mSpec);
2635 return !mResult.isEmpty();
2639 mResult = invitationDetailsFreeBusy(fb,
FreeBusy::Ptr(), mNoHtmlMode, mSpec);
2640 return !mResult.isEmpty();
2645 KDateTime::Spec mSpec;
2649InvitationFormatterHelper::InvitationFormatterHelper()
2654InvitationFormatterHelper::~InvitationFormatterHelper()
2658QString InvitationFormatterHelper::generateLinkURL(
const QString &
id)
2664class IncidenceFormatter::IncidenceCompareVisitor :
public Visitor
2667 IncidenceCompareVisitor() {}
2671 if (!existingIncidence) {
2675 if (!inc || !existingIncidence ||
2676 inc->revision() <= existingIncidence->revision()) {
2679 mExistingIncidence = existingIncidence;
2680 return incidence->
accept(*
this, incidence);
2683 QString result()
const
2685 if (mChanges.isEmpty()) {
2688 QString html = QLatin1String(
"<div align=\"left\"><ul><li>");
2689 html += mChanges.join(QLatin1String(
"</li><li>"));
2690 html += QLatin1String(
"</li><ul></div>");
2697 compareEvents(event, mExistingIncidence.dynamicCast<
Event>());
2698 compareIncidences(event, mExistingIncidence);
2699 return !mChanges.isEmpty();
2703 compareTodos(todo, mExistingIncidence.dynamicCast<
Todo>());
2704 compareIncidences(todo, mExistingIncidence);
2705 return !mChanges.isEmpty();
2709 compareIncidences(journal, mExistingIncidence);
2710 return !mChanges.isEmpty();
2715 return !mChanges.isEmpty();
2719 void compareEvents(
const Event::Ptr &newEvent,
2722 if (!oldEvent || !newEvent) {
2725 if (oldEvent->dtStart() != newEvent->dtStart() ||
2726 oldEvent->allDay() != newEvent->allDay()) {
2727 mChanges += i18n(
"The invitation starting time has been changed from %1 to %2",
2728 eventStartTimeStr(oldEvent), eventStartTimeStr(newEvent));
2730 if (oldEvent->dtEnd() != newEvent->dtEnd() ||
2731 oldEvent->allDay() != newEvent->allDay()) {
2732 mChanges += i18n(
"The invitation ending time has been changed from %1 to %2",
2733 eventEndTimeStr(oldEvent), eventEndTimeStr(newEvent));
2737 void compareTodos(
const Todo::Ptr &newTodo,
2740 if (!oldTodo || !newTodo) {
2744 if (!oldTodo->isCompleted() && newTodo->isCompleted()) {
2745 mChanges += i18n(
"The to-do has been completed");
2747 if (oldTodo->isCompleted() && !newTodo->isCompleted()) {
2748 mChanges += i18n(
"The to-do is no longer completed");
2750 if (oldTodo->percentComplete() != newTodo->percentComplete()) {
2751 const QString oldPer = i18n(
"%1%", oldTodo->percentComplete());
2752 const QString newPer = i18n(
"%1%", newTodo->percentComplete());
2753 mChanges += i18n(
"The task completed percentage has changed from %1 to %2",
2757 if (!oldTodo->hasStartDate() && newTodo->hasStartDate()) {
2758 mChanges += i18n(
"A to-do starting time has been added");
2760 if (oldTodo->hasStartDate() && !newTodo->hasStartDate()) {
2761 mChanges += i18n(
"The to-do starting time has been removed");
2763 if (oldTodo->hasStartDate() && newTodo->hasStartDate() &&
2764 oldTodo->dtStart() != newTodo->dtStart()) {
2765 mChanges += i18n(
"The to-do starting time has been changed from %1 to %2",
2770 if (!oldTodo->hasDueDate() && newTodo->hasDueDate()) {
2771 mChanges += i18n(
"A to-do due time has been added");
2773 if (oldTodo->hasDueDate() && !newTodo->hasDueDate()) {
2774 mChanges += i18n(
"The to-do due time has been removed");
2776 if (oldTodo->hasDueDate() && newTodo->hasDueDate() &&
2777 oldTodo->dtDue() != newTodo->dtDue()) {
2778 mChanges += i18n(
"The to-do due time has been changed from %1 to %2",
2787 if (!oldInc || !newInc) {
2791 if (oldInc->summary() != newInc->summary()) {
2792 mChanges += i18n(
"The summary has been changed to: \"%1\"",
2793 newInc->richSummary());
2796 if (oldInc->location() != newInc->location()) {
2797 mChanges += i18n(
"The location has been changed to: \"%1\"",
2798 newInc->richLocation());
2801 if (oldInc->description() != newInc->description()) {
2802 mChanges += i18n(
"The description has been changed to: \"%1\"",
2803 newInc->richDescription());
2808 for (Attendee::List::ConstIterator it = newAttendees.constBegin();
2809 it != newAttendees.constEnd(); ++it) {
2810 Attendee::Ptr oldAtt = oldInc->attendeeByMail((*it)->email());
2812 mChanges += i18n(
"Attendee %1 has been added", (*it)->fullName());
2814 if (oldAtt->status() != (*it)->status()) {
2815 mChanges += i18n(
"The status of attendee %1 has been changed to: %2",
2816 (*it)->fullName(), Stringify::attendeeStatus((*it)->status()));
2821 for (Attendee::List::ConstIterator it = oldAttendees.constBegin();
2822 it != oldAttendees.constEnd(); ++it) {
2823 if (!attendeeIsOrganizer(oldInc, (*it))) {
2824 Attendee::Ptr newAtt = newInc->attendeeByMail((*it)->email());
2826 mChanges += i18n(
"Attendee %1 has been removed", (*it)->fullName());
2834 QStringList mChanges;
2838QString InvitationFormatterHelper::makeLink(
const QString &
id,
const QString &text)
2840 if (!
id.startsWith(QLatin1String(
"ATTACH:"))) {
2841 QString res = QString::fromLatin1(
"<a href=\"%1\"><font size=\"-1\"><b>%2</b></font></a>").
2842 arg(generateLinkURL(
id), text);
2846 QString res = QString::fromLatin1(
"<a href=\"%1\">%2</a>").
2847 arg(generateLinkURL(
id), text);
2854static bool incidenceOwnedByMe(
const Calendar::Ptr &calendar,
2858 Q_UNUSED(incidence);
2862static QString inviteButton(InvitationFormatterHelper *helper,
2863 const QString &
id,
const QString &text)
2870 html += QLatin1String(
"<td style=\"border-width:2px;border-style:outset\">");
2871 if (!
id.isEmpty()) {
2872 html += helper->makeLink(
id, text);
2876 html += QLatin1String(
"</td>");
2880static QString inviteLink(InvitationFormatterHelper *helper,
2881 const QString &
id,
const QString &text)
2885 if (helper && !
id.isEmpty()) {
2886 html += helper->makeLink(
id, text);
2894 bool rsvpReq,
bool rsvpRec,
2895 InvitationFormatterHelper *helper)
2902 if (!rsvpReq && (incidence && incidence->revision() == 0)) {
2904 html += inviteButton(helper, QLatin1String(
"record"), i18n(
"Record"));
2907 html += inviteButton(helper, QLatin1String(
"delete"), i18n(
"Move to Trash"));
2912 html += inviteButton(helper, QLatin1String(
"accept"),
2913 i18nc(
"accept invitation",
"Accept"));
2916 html += inviteButton(helper, QLatin1String(
"accept_conditionally"),
2917 i18nc(
"Accept invitation conditionally",
"Accept cond."));
2920 html += inviteButton(helper, QLatin1String(
"counter"),
2921 i18nc(
"invitation counter proposal",
"Counter proposal"));
2924 html += inviteButton(helper, QLatin1String(
"decline"),
2925 i18nc(
"decline invitation",
"Decline"));
2928 if (!rsvpRec || (incidence && incidence->revision() > 0)) {
2930 html += inviteButton(helper, QLatin1String(
"delegate"),
2931 i18nc(
"delegate inviation to another",
"Delegate"));
2934 html += inviteButton(helper, QLatin1String(
"forward"), i18nc(
"forward request to another",
"Forward"));
2937 if (incidence && incidence->type() == Incidence::TypeEvent) {
2938 html += inviteButton(helper, QLatin1String(
"check_calendar"),
2939 i18nc(
"look for scheduling conflicts",
"Check my calendar"));
2946 InvitationFormatterHelper *helper)
2954 html += inviteButton(helper, QLatin1String(
"accept_counter"), i18n(
"Accept"));
2957 html += inviteButton(helper, QLatin1String(
"decline_counter"), i18n(
"Decline"));
2961 if (incidence->type() == Incidence::TypeTodo) {
2962 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my to-do list"));
2964 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my calendar"));
2971 InvitationFormatterHelper *helper)
2979 if (incidence->type() == Incidence::TypeTodo) {
2980 html += inviteLink(helper, QLatin1String(
"reply"),
2981 i18n(
"Record invitation in my to-do list"));
2983 html += inviteLink(helper, QLatin1String(
"reply"),
2984 i18n(
"Record invitation in my calendar"));
2990static QString recordResponseButtons(
const Incidence::Ptr &incidence,
2991 InvitationFormatterHelper *helper)
2999 if (incidence->type() == Incidence::TypeTodo) {
3000 html += inviteLink(helper, QLatin1String(
"reply"),
3001 i18n(
"Record response in my to-do list"));
3003 html += inviteLink(helper, QLatin1String(
"reply"),
3004 i18n(
"Record response in my calendar"));
3011 InvitationFormatterHelper *helper)
3020 if (incidence->type() == Incidence::TypeTodo) {
3021 html += inviteButton(helper, QLatin1String(
"cancel"),
3022 i18n(
"Remove invitation from my to-do list"));
3024 html += inviteButton(helper, QLatin1String(
"cancel"),
3025 i18n(
"Remove invitation from my calendar"));
3036static QString formatICalInvitationHelper(QString invitation,
3038 InvitationFormatterHelper *helper,
3040 KDateTime::Spec spec,
3041 const QString &sender,
3042 bool outlookCompareStyle)
3044 if (invitation.isEmpty()) {
3054 kDebug() <<
"Failed to parse the scheduling message";
3062 incBase->shiftTimes(mCalendar->timeSpec(), KDateTime::Spec::LocalZone());
3066 if (incBase && helper->calendar()) {
3067 existingIncidence = helper->calendar()->incidence(incBase->uid());
3069 if (!incidenceOwnedByMe(helper->calendar(), existingIncidence)) {
3070 existingIncidence.clear();
3072 if (!existingIncidence) {
3074 for (Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it) {
3075 if ((*it)->schedulingID() == incBase->uid() &&
3076 incidenceOwnedByMe(helper->calendar(), *it)) {
3077 existingIncidence = *it;
3088 int incRevision = 0;
3089 if (inc && inc->type() != Incidence::TypeFreeBusy) {
3094 QString html = QLatin1String(
"<div align=\"center\" style=\"border:solid 1px;\">");
3096 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
3098 if (!headerVisitor.act(inc, existingIncidence, msg, sender)) {
3101 html += htmlAddTag(QLatin1String(
"h3"), headerVisitor.result());
3103 if (outlookCompareStyle ||
3104 msg->method() == iTIPDeclineCounter) {
3106 IncidenceFormatter::InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3108 if (msg->method() == iTIPRequest || msg->method() == iTIPReply ||
3109 msg->method() == iTIPDeclineCounter) {
3110 if (inc && existingIncidence &&
3111 incRevision < existingIncidence->revision()) {
3112 bodyOk = bodyVisitor.act(existingIncidence, inc, msg, sender);
3114 bodyOk = bodyVisitor.act(inc, existingIncidence, msg, sender);
3120 html += bodyVisitor.result();
3126 InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3130 html += bodyVisitor.result();
3132 if (msg->method() == iTIPRequest) {
3133 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
3134 if (compareVisitor.act(inc, existingIncidence)) {
3135 html += QLatin1String(
"<p align=\"left\">");
3136 if (senderIsOrganizer(inc, sender)) {
3137 html += i18n(
"The following changes have been made by the organizer:");
3138 }
else if (!sender.isEmpty()) {
3139 html += i18n(
"The following changes have been made by %1:", sender);
3141 html += i18n(
"The following changes have been made:");
3143 html += QLatin1String(
"</p>");
3144 html += compareVisitor.result();
3147 if (msg->method() == iTIPReply) {
3148 IncidenceCompareVisitor compareVisitor;
3149 if (compareVisitor.act(inc, existingIncidence)) {
3150 html += QLatin1String(
"<p align=\"left\">");
3151 if (!sender.isEmpty()) {
3152 html += i18n(
"The following changes have been made by %1:", sender);
3154 html += i18n(
"The following changes have been made by an attendee:");
3156 html += QLatin1String(
"</p>");
3157 html += compareVisitor.result();
3163 bool myInc = iamOrganizer(inc);
3166 bool rsvpRec =
false;
3170 if (!rsvpIncidence && inc && incRevision > 0) {
3171 rsvpIncidence = inc;
3173 if (rsvpIncidence) {
3174 ea = findMyAttendee(rsvpIncidence);
3186 bool isDelegated =
false;
3189 if (!inc->attendees().isEmpty()) {
3190 a = inc->attendees().first();
3195 role = Stringify::attendeeRole(a->role());
3199 bool rsvpReq = rsvpRequested(inc);
3202 if (rsvpRec && inc) {
3203 if (incRevision == 0) {
3204 tStr = i18n(
"Your <b>%1</b> response has been recorded",
3205 Stringify::attendeeStatus(ea->status()));
3207 tStr = i18n(
"Your status for this invitation is <b>%1</b>",
3208 Stringify::attendeeStatus(ea->status()));
3211 }
else if (msg->method() == iTIPCancel) {
3212 tStr = i18n(
"This invitation was canceled");
3213 }
else if (msg->method() == iTIPAdd) {
3214 tStr = i18n(
"This invitation was accepted");
3215 }
else if (msg->method() == iTIPDeclineCounter) {
3217 tStr = rsvpRequestedStr(rsvpReq, role);
3220 tStr = rsvpRequestedStr(rsvpReq, role);
3222 tStr = i18n(
"Awaiting delegation response");
3225 html += QLatin1String(
"<br>");
3226 html += QLatin1String(
"<i><u>") + tStr + QLatin1String(
"</u></i>");
3231 if (inc && incRevision == 0) {
3232 QString statStr = myStatusStr(inc);
3233 if (!statStr.isEmpty()) {
3234 html += QLatin1String(
"<br>");
3235 html += QLatin1String(
"<i>") + statStr + QLatin1String(
"</i>");
3242 html += QLatin1String(
"<p>");
3243 html += QLatin1String(
"<table border=\"0\" align=\"center\" cellspacing=\"4\"><tr>");
3245 switch (msg->method()) {
3251 if (inc && incRevision > 0 && (existingIncidence || !helper->calendar())) {
3252 html += recordButtons(inc, helper);
3257 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3259 html += responseButtons(inc,
false,
false, helper);
3266 html += cancelButtons(inc, helper);
3276 if (replyMeansCounter(inc)) {
3277 html += QLatin1String(
"<tr>") + counterButtons(inc, helper) + QLatin1String(
"</tr>");
3286 a = findDelegatedFromMyAttendee(inc);
3290 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3296 if (!inc->attendees().isEmpty()) {
3297 a = inc->attendees().first();
3299 if (a && helper->calendar()) {
3300 ea = findAttendee(existingIncidence, a->email());
3304 const QString tStr = i18n(
"The <b>%1</b> response has been recorded",
3305 Stringify::attendeeStatus(ea->status()));
3306 html += inviteButton(helper, QString(), htmlAddTag(QLatin1String(
"i"), tStr));
3309 html += recordResponseButtons(inc, helper);
3317 html += counterButtons(inc, helper);
3321 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3329 html += QLatin1String(
"</tr></table>");
3333 html += invitationRsvpList(existingIncidence, a);
3335 html += invitationAttendeeList(inc);
3339 html += QLatin1String(
"</div>");
3342 html += invitationAttachments(helper, inc);
3350 InvitationFormatterHelper *helper,
3351 bool outlookCompareStyle)
3353 return formatICalInvitationHelper(invitation, calendar, helper,
false,
3354 KSystemTimeZones::local(), QString(),
3355 outlookCompareStyle);
3360 InvitationFormatterHelper *helper,
3361 const QString &sender,
3362 bool outlookCompareStyle)
3364 return formatICalInvitationHelper(invitation, calendar, helper,
true,
3365 KSystemTimeZones::local(), sender,
3366 outlookCompareStyle);
3374class KCalUtils::IncidenceFormatter::ToolTipVisitor :
public Visitor
3378 : mRichText(true), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3382 const QDate &date=QDate(),
bool richText=
true,
3383 KDateTime::Spec spec=KDateTime::Spec())
3385 mCalendar = calendar;
3388 mRichText = richText;
3390 mResult = QLatin1String(
"");
3391 return incidence ? incidence->accept(*
this, incidence) :
false;
3395 const QDate &date=QDate(),
bool richText=
true,
3396 KDateTime::Spec spec=KDateTime::Spec())
3398 mLocation = location;
3400 mRichText = richText;
3402 mResult = QLatin1String(
"");
3403 return incidence ? incidence->accept(*
this, incidence) :
false;
3406 QString result()
const {
3416 QString dateRangeText(
const Event::Ptr &event,
const QDate &date);
3417 QString dateRangeText(
const Todo::Ptr &todo,
const QDate &date);
3421 QString generateToolTip(
const Incidence::Ptr &incidence, QString dtRangeText);
3428 KDateTime::Spec mSpec;
3432QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Event::Ptr &event,
3439 KDateTime startDt =
event->
dtStart();
3440 KDateTime endDt =
event->dtEnd();
3441 if (event->recurs()) {
3442 if (date.isValid()) {
3443 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3444 int diffDays = startDt.daysTo(kdt);
3445 kdt = kdt.addSecs(-1);
3446 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
3447 if (event->hasEndDate()) {
3448 endDt = endDt.addDays(diffDays);
3449 if (startDt > endDt) {
3450 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
3451 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
3457 if (event->isMultiDay()) {
3459 ret += QLatin1String(
"<br>") + i18nc(
"Event start",
"<i>From:</i> %1", tmp);
3462 ret += QLatin1String(
"<br>") + i18nc(
"Event end",
"<i>To:</i> %1", tmp);
3466 ret += QLatin1String(
"<br>") +
3467 i18n(
"<i>Date:</i> %1",
dateToString(startDt,
false, mSpec));
3468 if (!event->allDay()) {
3469 const QString dtStartTime =
timeToString(startDt,
true, mSpec);
3470 const QString dtEndTime =
timeToString(endDt,
true, mSpec);
3471 if (dtStartTime == dtEndTime) {
3473 tmp = QLatin1String(
"<br>") +
3474 i18nc(
"time for event",
"<i>Time:</i> %1",
3477 tmp = QLatin1String(
"<br>") +
3478 i18nc(
"time range for event",
3479 "<i>Time:</i> %1 - %2",
3480 dtStartTime, dtEndTime);
3485 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3488QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Todo::Ptr &todo,
3493 if (todo->hasStartDate()) {
3494 KDateTime startDt = todo->dtStart();
3495 if (todo->recurs() && date.isValid()) {
3496 startDt.setDate(date);
3498 ret += QLatin1String(
"<br>") +
3499 i18n(
"<i>Start:</i> %1",
dateToString(startDt,
false, mSpec));
3502 if (todo->hasDueDate()) {
3503 KDateTime dueDt = todo->dtDue();
3504 if (todo->recurs() && date.isValid()) {
3505 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3506 kdt = kdt.addSecs(-1);
3507 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
3509 ret += QLatin1String(
"<br>") +
3510 i18n(
"<i>Due:</i> %1",
3516 if (todo->priority() > 0) {
3517 ret += QLatin1String(
"<br>");
3518 ret += QLatin1String(
"<i>") + i18n(
"Priority:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3519 ret += QString::number(todo->priority());
3522 ret += QLatin1String(
"<br>");
3523 if (todo->isCompleted()) {
3524 ret += QLatin1String(
"<i>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3527 ret += QLatin1String(
"<i>")+ i18n(
"Percent Done:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3528 ret += i18n(
"%1%", todo->percentComplete());
3531 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3534QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Journal::Ptr &journal)
3538 if (journal->dtStart().isValid()) {
3539 ret += QLatin1String(
"<br>") +
3540 i18n(
"<i>Date:</i> %1",
dateToString(journal->dtStart(),
false, mSpec));
3542 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3545QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const FreeBusy::Ptr &fb)
3549 ret = QLatin1String(
"<br>") +
3550 i18n(
"<i>Period start:</i> %1",
3552 ret += QLatin1String(
"<br>") +
3553 i18n(
"<i>Period start:</i> %1",
3555 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3558bool IncidenceFormatter::ToolTipVisitor::visit(
Event::Ptr event)
3560 mResult = generateToolTip(event, dateRangeText(event, mDate));
3561 return !mResult.isEmpty();
3564bool IncidenceFormatter::ToolTipVisitor::visit(
Todo::Ptr todo)
3566 mResult = generateToolTip(todo, dateRangeText(todo, mDate));
3567 return !mResult.isEmpty();
3570bool IncidenceFormatter::ToolTipVisitor::visit(
Journal::Ptr journal)
3572 mResult = generateToolTip(journal, dateRangeText(journal));
3573 return !mResult.isEmpty();
3576bool IncidenceFormatter::ToolTipVisitor::visit(
FreeBusy::Ptr fb)
3579 mResult = QLatin1String(
"<qt><b>") +
3580 i18n(
"Free/Busy information for %1", fb->organizer()->fullName()) +
3581 QLatin1String(
"</b>");
3582 mResult += dateRangeText(fb);
3583 mResult += QLatin1String(
"</qt>");
3584 return !mResult.isEmpty();
3587static QString tooltipPerson(
const QString &email,
const QString &name,
Attendee::PartStat status)
3590 const QString printName = searchName(email, name);
3593 const QString iconPath = rsvpStatusIconPath(status);
3596 QString personString;
3597 if (!iconPath.isEmpty()) {
3598 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3600 if (status != Attendee::None) {
3601 personString += i18nc(
"attendee name (attendee status)",
"%1 (%2)",
3602 printName.isEmpty() ? email : printName,
3603 Stringify::attendeeStatus(status));
3605 personString += i18n(
"%1", printName.isEmpty() ? email : printName);
3607 return personString;
3610static QString tooltipFormatOrganizer(
const QString &email,
const QString &name)
3613 const QString printName = searchName(email, name);
3616 const QString iconPath =
3617 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
3620 QString personString;
3621 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3622 personString += (printName.isEmpty() ? email : printName);
3623 return personString;
3626static QString tooltipFormatAttendeeRoleList(
const Incidence::Ptr &incidence,
3630 const QString etc = i18nc(
"elipsis",
"...");
3634 Attendee::List::ConstIterator it;
3637 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
3639 if (a->role() != role) {
3643 if (attendeeIsOrganizer(incidence, a)) {
3647 if (i == maxNumAtts) {
3648 tmpStr += QLatin1String(
" ") + etc;
3651 tmpStr += QLatin1String(
" ") + tooltipPerson(a->email(), a->name(),
3652 showStatus ? a->status() : Attendee::None);
3653 if (!a->delegator().isEmpty()) {
3654 tmpStr += i18n(
" (delegated by %1)", a->delegator());
3656 if (!a->delegate().isEmpty()) {
3657 tmpStr += i18n(
" (delegated to %1)", a->delegate());
3659 tmpStr += QLatin1String(
"<br>");
3662 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
3668static QString tooltipFormatAttendees(
const Calendar::Ptr &calendar,
3671 QString tmpStr, str;
3674 int attendeeCount = incidence->attendees().count();
3675 if (attendeeCount > 1 ||
3676 (attendeeCount == 1 &&
3677 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
3678 tmpStr += QLatin1String(
"<i>") + i18n(
"Organizer:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3679 tmpStr += QLatin1String(
" ") + tooltipFormatOrganizer(incidence->organizer()->email(),
3680 incidence->organizer()->name());
3685 const bool showStatus = attendeeCount > 0 && incOrganizerOwnsCalendar(calendar, incidence);
3688 str = tooltipFormatAttendeeRoleList(incidence,
Attendee::Chair, showStatus);
3689 if (!str.isEmpty()) {
3690 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Chair:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3696 if (!str.isEmpty()) {
3697 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Required Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3703 if (!str.isEmpty()) {
3704 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Optional Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3710 if (!str.isEmpty()) {
3711 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Observers:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3718QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
const Incidence::Ptr &incidence,
3719 QString dtRangeText)
3721 int maxDescLen = 120;
3728 QString tmp = QLatin1String(
"<qt>");
3731 tmp += QLatin1String(
"<b>") + incidence->richSummary() + QLatin1String(
"</b>");
3732 tmp += QLatin1String(
"<hr>");
3734 QString calStr = mLocation;
3738 if (!calStr.isEmpty()) {
3739 tmp += QLatin1String(
"<i>") + i18n(
"Calendar:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3745 if (!incidence->location().isEmpty()) {
3746 tmp += QLatin1String(
"<br>");
3747 tmp += QLatin1String(
"<i>") + i18n(
"Location:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3748 tmp += incidence->richLocation();
3752 if (!durStr.isEmpty()) {
3753 tmp += QLatin1String(
"<br>");
3754 tmp += QLatin1String(
"<i>") + i18n(
"Duration:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3758 if (incidence->recurs()) {
3759 tmp += QLatin1String(
"<br>");
3760 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3764 if (incidence->hasRecurrenceId()) {
3765 tmp += QLatin1String(
"<br>");
3766 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3767 tmp += i18n(
"Exception");
3770 if (!incidence->description().isEmpty()) {
3771 QString desc(incidence->description());
3772 if (!incidence->descriptionIsRich()) {
3773 if (desc.length() > maxDescLen) {
3774 desc = desc.left(maxDescLen) + i18nc(
"elipsis",
"...");
3776 desc = Qt::escape(desc).replace(QLatin1Char(
'\n'), QLatin1String(
"<br>"));
3780 tmp += QLatin1String(
"<hr>");
3781 tmp += QLatin1String(
"<i>") + i18n(
"Description:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3783 tmp += QLatin1String(
"<hr>");
3786 int reminderCount = incidence->alarms().count();
3787 if (reminderCount > 0 && incidence->hasEnabledAlarms()) {
3788 tmp += QLatin1String(
"<br>");
3789 tmp += QLatin1String(
"<i>") + i18np(
"Reminder:",
"Reminders:", reminderCount) + QLatin1String(
"</i>") + QLatin1String(
" ");
3793 tmp += QLatin1String(
"<br>");
3794 tmp += tooltipFormatAttendees(mCalendar, incidence);
3796 int categoryCount = incidence->categories().count();
3797 if (categoryCount > 0) {
3798 tmp += QLatin1String(
"<br>");
3799 tmp += QLatin1String(
"<i>") + i18np(
"Category:",
"Categories:", categoryCount) + QLatin1String(
"</i>") +QLatin1String(
" ");
3800 tmp += incidence->categories().join(QLatin1String(
", "));
3803 tmp += QLatin1String(
"</qt>");
3812 KDateTime::Spec spec)
3815 if (incidence && v.act(sourceName, incidence, date, richText, spec)) {
3830 if (!incidence->summary().isEmpty()) {
3831 body += i18n(
"Summary: %1\n", incidence->richSummary());
3833 if (!incidence->organizer()->isEmpty()) {
3834 body += i18n(
"Organizer: %1\n", incidence->organizer()->fullName());
3836 if (!incidence->location().isEmpty()) {
3837 body += i18n(
"Location: %1\n", incidence->richLocation());
3844class KCalUtils::IncidenceFormatter::MailBodyVisitor :
public Visitor
3848 : mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3853 mResult = QLatin1String(
"");
3854 return incidence ? incidence->accept(*
this, incidence) :
false;
3856 QString result()
const
3867 mResult = i18n(
"This is a Free Busy Object");
3868 return !mResult.isEmpty();
3871 KDateTime::Spec mSpec;
3875bool IncidenceFormatter::MailBodyVisitor::visit(
Event::Ptr event)
3877 QString recurrence[]= {
3878 i18nc(
"no recurrence",
"None"),
3879 i18nc(
"event recurs by minutes",
"Minutely"),
3880 i18nc(
"event recurs by hours",
"Hourly"),
3881 i18nc(
"event recurs by days",
"Daily"),
3882 i18nc(
"event recurs by weeks",
"Weekly"),
3883 i18nc(
"event recurs same position (e.g. first monday) each month",
"Monthly Same Position"),
3884 i18nc(
"event recurs same day each month",
"Monthly Same Day"),
3885 i18nc(
"event recurs same month each year",
"Yearly Same Month"),
3886 i18nc(
"event recurs same day each year",
"Yearly Same Day"),
3887 i18nc(
"event recurs same position (e.g. first monday) each year",
"Yearly Same Position")
3890 mResult = mailBodyIncidence(event);
3891 mResult += i18n(
"Start Date: %1\n",
dateToString(event->dtStart(),
true, mSpec));
3892 if (!event->allDay()) {
3893 mResult += i18n(
"Start Time: %1\n",
timeToString(event->dtStart(),
true, mSpec));
3895 if (event->dtStart() != event->dtEnd()) {
3896 mResult += i18n(
"End Date: %1\n",
dateToString(event->dtEnd(),
true, mSpec));
3898 if (!event->allDay()) {
3899 mResult += i18n(
"End Time: %1\n",
timeToString(event->dtEnd(),
true, mSpec));
3901 if (event->recurs()) {
3904 mResult += i18n(
"Recurs: %1\n", recurrence[ recur->
recurrenceType() ]);
3905 mResult += i18n(
"Frequency: %1\n", event->recurrence()->frequency());
3908 mResult += i18np(
"Repeats once",
"Repeats %1 times", recur->
duration());
3909 mResult += QLatin1Char(
'\n');
3914 if (event->allDay()) {
3915 endstr = KGlobal::locale()->formatDate(recur->
endDate());
3917 endstr = KGlobal::locale()->formatDateTime(recur->
endDateTime().dateTime());
3919 mResult += i18n(
"Repeat until: %1\n", endstr);
3921 mResult += i18n(
"Repeats forever\n");
3926 if (!event->description().isEmpty()) {
3928 if (event->descriptionIsRich() ||
3929 event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
3931 descStr = cleanHtml(event->description());
3933 descStr =
event->description();
3935 if (!descStr.isEmpty()) {
3936 mResult += i18n(
"Details:\n%1\n", descStr);
3939 return !mResult.isEmpty();
3942bool IncidenceFormatter::MailBodyVisitor::visit(
Todo::Ptr todo)
3944 mResult = mailBodyIncidence(todo);
3946 if (todo->hasStartDate() && todo->dtStart().isValid()) {
3947 mResult += i18n(
"Start Date: %1\n",
dateToString(todo->dtStart(
false),
true, mSpec));
3948 if (!todo->allDay()) {
3949 mResult += i18n(
"Start Time: %1\n",
timeToString(todo->dtStart(
false),
true, mSpec));
3952 if (todo->hasDueDate() && todo->dtDue().isValid()) {
3953 mResult += i18n(
"Due Date: %1\n",
dateToString(todo->dtDue(),
true, mSpec));
3954 if (!todo->allDay()) {
3955 mResult += i18n(
"Due Time: %1\n",
timeToString(todo->dtDue(),
true, mSpec));
3958 QString details = todo->richDescription();
3959 if (!details.isEmpty()) {
3960 mResult += i18n(
"Details:\n%1\n", details);
3962 return !mResult.isEmpty();
3965bool IncidenceFormatter::MailBodyVisitor::visit(
Journal::Ptr journal)
3967 mResult = mailBodyIncidence(journal);
3968 mResult += i18n(
"Date: %1\n",
dateToString(journal->dtStart(),
true, mSpec));
3969 if (!journal->allDay()) {
3970 mResult += i18n(
"Time: %1\n",
timeToString(journal->dtStart(),
true, mSpec));
3972 if (!journal->description().isEmpty()) {
3973 mResult += i18n(
"Text of the journal:\n%1\n", journal->richDescription());
3975 return !mResult.isEmpty();
3980 KDateTime::Spec spec)
3987 if (v.act(incidence, spec)) {
3997 if (incidence->allDay()) {
3998 endstr = KGlobal::locale()->formatDate(incidence->recurrence()->endDate());
4000 endstr = KGlobal::locale()->formatDateTime(incidence->recurrence()->endDateTime());
4012 if (incidence->hasRecurrenceId()) {
4013 return QLatin1String(
"Recurrence exception");
4016 if (!incidence->recurs()) {
4017 return i18n(
"No recurrence");
4019 static QStringList dayList;
4020 if (dayList.isEmpty()) {
4021 dayList.append(i18n(
"31st Last"));
4022 dayList.append(i18n(
"30th Last"));
4023 dayList.append(i18n(
"29th Last"));
4024 dayList.append(i18n(
"28th Last"));
4025 dayList.append(i18n(
"27th Last"));
4026 dayList.append(i18n(
"26th Last"));
4027 dayList.append(i18n(
"25th Last"));
4028 dayList.append(i18n(
"24th Last"));
4029 dayList.append(i18n(
"23rd Last"));
4030 dayList.append(i18n(
"22nd Last"));
4031 dayList.append(i18n(
"21st Last"));
4032 dayList.append(i18n(
"20th Last"));
4033 dayList.append(i18n(
"19th Last"));
4034 dayList.append(i18n(
"18th Last"));
4035 dayList.append(i18n(
"17th Last"));
4036 dayList.append(i18n(
"16th Last"));
4037 dayList.append(i18n(
"15th Last"));
4038 dayList.append(i18n(
"14th Last"));
4039 dayList.append(i18n(
"13th Last"));
4040 dayList.append(i18n(
"12th Last"));
4041 dayList.append(i18n(
"11th Last"));
4042 dayList.append(i18n(
"10th Last"));
4043 dayList.append(i18n(
"9th Last"));
4044 dayList.append(i18n(
"8th Last"));
4045 dayList.append(i18n(
"7th Last"));
4046 dayList.append(i18n(
"6th Last"));
4047 dayList.append(i18n(
"5th Last"));
4048 dayList.append(i18n(
"4th Last"));
4049 dayList.append(i18n(
"3rd Last"));
4050 dayList.append(i18n(
"2nd Last"));
4051 dayList.append(i18nc(
"last day of the month",
"Last"));
4052 dayList.append(i18nc(
"unknown day of the month",
"unknown"));
4053 dayList.append(i18n(
"1st"));
4054 dayList.append(i18n(
"2nd"));
4055 dayList.append(i18n(
"3rd"));
4056 dayList.append(i18n(
"4th"));
4057 dayList.append(i18n(
"5th"));
4058 dayList.append(i18n(
"6th"));
4059 dayList.append(i18n(
"7th"));
4060 dayList.append(i18n(
"8th"));
4061 dayList.append(i18n(
"9th"));
4062 dayList.append(i18n(
"10th"));
4063 dayList.append(i18n(
"11th"));
4064 dayList.append(i18n(
"12th"));
4065 dayList.append(i18n(
"13th"));
4066 dayList.append(i18n(
"14th"));
4067 dayList.append(i18n(
"15th"));
4068 dayList.append(i18n(
"16th"));
4069 dayList.append(i18n(
"17th"));
4070 dayList.append(i18n(
"18th"));
4071 dayList.append(i18n(
"19th"));
4072 dayList.append(i18n(
"20th"));
4073 dayList.append(i18n(
"21st"));
4074 dayList.append(i18n(
"22nd"));
4075 dayList.append(i18n(
"23rd"));
4076 dayList.append(i18n(
"24th"));
4077 dayList.append(i18n(
"25th"));
4078 dayList.append(i18n(
"26th"));
4079 dayList.append(i18n(
"27th"));
4080 dayList.append(i18n(
"28th"));
4081 dayList.append(i18n(
"29th"));
4082 dayList.append(i18n(
"30th"));
4083 dayList.append(i18n(
"31st"));
4086 const int weekStart = KGlobal::locale()->weekStartDay();
4088 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
4092 QString txt, recurStr;
4093 static QString noRecurrence = i18n(
"No recurrence");
4095 case Recurrence::rNone:
4096 return noRecurrence;
4098 case Recurrence::rMinutely:
4100 recurStr = i18np(
"Recurs every minute until %2",
4101 "Recurs every %1 minutes until %2",
4102 recur->
frequency(), recurEnd(incidence));
4104 recurStr += i18nc(
"number of occurrences",
4105 " (<numid>%1</numid> occurrences)",
4109 recurStr = i18np(
"Recurs every minute",
4110 "Recurs every %1 minutes", recur->
frequency());
4114 case Recurrence::rHourly:
4116 recurStr = i18np(
"Recurs hourly until %2",
4117 "Recurs every %1 hours until %2",
4118 recur->
frequency(), recurEnd(incidence));
4120 recurStr += i18nc(
"number of occurrences",
4121 " (<numid>%1</numid> occurrences)",
4125 recurStr = i18np(
"Recurs hourly",
"Recurs every %1 hours", recur->
frequency());
4129 case Recurrence::rDaily:
4131 recurStr = i18np(
"Recurs daily until %2",
4132 "Recurs every %1 days until %2",
4133 recur->
frequency(), recurEnd(incidence));
4135 recurStr += i18nc(
"number of occurrences",
4136 " (<numid>%1</numid> occurrences)",
4140 recurStr = i18np(
"Recurs daily",
"Recurs every %1 days", recur->
frequency());
4144 case Recurrence::rWeekly:
4146 bool addSpace =
false;
4147 for (
int i = 0; i < 7; ++i) {
4148 if (recur->
days().testBit((i + weekStart + 6) % 7)) {
4150 dayNames.append(i18nc(
"separator for list of days",
", "));
4152 dayNames.append(calSys->weekDayName(((i + weekStart + 6) % 7) + 1,
4153 KCalendarSystem::ShortDayName));
4157 if (dayNames.isEmpty()) {
4158 dayNames = i18nc(
"Recurs weekly on no days",
"no days");
4161 recurStr = i18ncp(
"Recurs weekly on [list of days] until end-date",
4162 "Recurs weekly on %2 until %3",
4163 "Recurs every <numid>%1</numid> weeks on %2 until %3",
4164 recur->
frequency(), dayNames, recurEnd(incidence));
4166 recurStr += i18nc(
"number of occurrences",
4167 " (<numid>%1</numid> occurrences)",
4171 recurStr = i18ncp(
"Recurs weekly on [list of days]",
4172 "Recurs weekly on %2",
4173 "Recurs every <numid>%1</numid> weeks on %2",
4178 case Recurrence::rMonthlyPos:
4183 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...]"
4184 " weekdayname until end-date",
4185 "Recurs every month on the %2 %3 until %4",
4186 "Recurs every <numid>%1</numid> months on the %2 %3 until %4",
4188 dayList[rule.pos() + 31],
4189 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4190 recurEnd(incidence));
4192 recurStr += i18nc(
"number of occurrences",
4193 " (<numid>%1</numid> occurrences)",
4197 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...] weekdayname",
4198 "Recurs every month on the %2 %3",
4199 "Recurs every %1 months on the %2 %3",
4201 dayList[rule.pos() + 31],
4202 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName));
4207 case Recurrence::rMonthlyDay:
4212 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day until end-date",
4213 "Recurs monthly on the %2 day until %3",
4214 "Recurs every %1 months on the %2 day until %3",
4217 recurEnd(incidence));
4219 recurStr += i18nc(
"number of occurrences",
4220 " (<numid>%1</numid> occurrences)",
4224 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day",
4225 "Recurs monthly on the %2 day",
4226 "Recurs every <numid>%1</numid> month on the %2 day",
4228 dayList[days + 31]);
4233 case Recurrence::rYearlyMonth:
4237 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]"
4239 "Recurs yearly on %2 %3 until %4",
4240 "Recurs every %1 years on %2 %3 until %4",
4244 recurEnd(incidence));
4246 recurStr += i18nc(
"number of occurrences",
4247 " (<numid>%1</numid> occurrences)",
4253 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]",
4254 "Recurs yearly on %2 %3",
4255 "Recurs every %1 years on %2 %3",
4262 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4263 "Recurs yearly on %1 %2",
4266 dayList[ recur->
startDate().day() + 31 ]);
4268 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4269 "Recurs yearly on %1 %2",
4270 calSys->monthName(recur->
startDate().month(),
4272 dayList[ recur->
startDate().day() + 31 ]);
4278 case Recurrence::rYearlyDay:
4279 if (!recur->
yearDays().isEmpty()) {
4281 recurStr = i18ncp(
"Recurs every N years on day N until end-date",
4282 "Recurs every year on day <numid>%2</numid> until %3",
4283 "Recurs every <numid>%1</numid> years"
4284 " on day <numid>%2</numid> until %3",
4287 recurEnd(incidence));
4289 recurStr += i18nc(
"number of occurrences",
4290 " (<numid>%1</numid> occurrences)",
4294 recurStr = i18ncp(
"Recurs every N YEAR[S] on day N",
4295 "Recurs every year on day <numid>%2</numid>",
4296 "Recurs every <numid>%1</numid> years"
4297 " on day <numid>%2</numid>",
4302 case Recurrence::rYearlyPos:
4307 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4308 "of monthname until end-date",
4309 "Every year on the %2 %3 of %4 until %5",
4310 "Every <numid>%1</numid> years on the %2 %3 of %4"
4313 dayList[rule.pos() + 31],
4314 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4316 recurEnd(incidence));
4318 recurStr += i18nc(
"number of occurrences",
4319 " (<numid>%1</numid> occurrences)",
4323 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4325 "Every year on the %2 %3 of %4",
4326 "Every <numid>%1</numid> years on the %2 %3 of %4",
4328 dayList[rule.pos() + 31],
4329 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4337 if (recurStr.isEmpty()) {
4338 recurStr = i18n(
"Incidence recurs");
4343 DateTimeList::ConstIterator il;
4345 for (il = l.constBegin(); il != l.constEnd(); ++il) {
4347 case Recurrence::rMinutely:
4348 exStr << i18n(
"minute %1", (*il).time().minute());
4350 case Recurrence::rHourly:
4351 exStr << KGlobal::locale()->formatTime((*il).time());
4353 case Recurrence::rDaily:
4354 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4356 case Recurrence::rWeekly:
4357 exStr << calSys->weekDayName((*il).date(), KCalendarSystem::ShortDayName);
4359 case Recurrence::rMonthlyPos:
4360 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4362 case Recurrence::rMonthlyDay:
4363 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4365 case Recurrence::rYearlyMonth:
4366 exStr << calSys->monthName((*il).date(), KCalendarSystem::LongName);
4368 case Recurrence::rYearlyDay:
4369 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4371 case Recurrence::rYearlyPos:
4372 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4378 DateList::ConstIterator dl;
4379 for (dl = d.constBegin(); dl != d.constEnd(); ++dl) {
4381 case Recurrence::rDaily:
4382 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4384 case Recurrence::rWeekly:
4387 if (exStr.isEmpty()) {
4388 exStr << i18np(
"1 day",
"%1 days", recur->exDates().count());
4391 case Recurrence::rMonthlyPos:
4392 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4394 case Recurrence::rMonthlyDay:
4395 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4397 case Recurrence::rYearlyMonth:
4398 exStr << calSys->monthName((*dl), KCalendarSystem::LongName);
4400 case Recurrence::rYearlyDay:
4401 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4403 case Recurrence::rYearlyPos:
4404 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4409 if (!exStr.isEmpty()) {
4410 recurStr = i18n(
"%1 (excluding %2)", recurStr, exStr.join(QLatin1String(
",")));
4418 const KDateTime::Spec &spec)
4420 if (spec.isValid()) {
4423 if (spec.timeZone() != KSystemTimeZones::local()) {
4424 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4427 return KGlobal::locale()->formatTime(date.toTimeSpec(spec).time(), !shortfmt) + timeZone;
4429 return KGlobal::locale()->formatTime(date.time(), !shortfmt);
4435 const KDateTime::Spec &spec)
4437 if (spec.isValid()) {
4440 if (spec.timeZone() != KSystemTimeZones::local()) {
4441 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4445 KGlobal::locale()->formatDate(date.toTimeSpec(spec).date(),
4446 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) +
4450 KGlobal::locale()->formatDate(date.date(),
4451 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4458 const KDateTime::Spec &spec)
4464 if (spec.isValid()) {
4466 if (spec.timeZone() != KSystemTimeZones::local()) {
4467 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4470 return KGlobal::locale()->formatDateTime(
4471 date.toTimeSpec(spec).dateTime(),
4472 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) + timeZone;
4474 return KGlobal::locale()->formatDateTime(
4476 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4484 Q_UNUSED(incidence);
4488static QString secs2Duration(
int secs)
4491 int days = secs / 86400;
4493 tmp += i18np(
"1 day",
"%1 days", days);
4494 tmp += QLatin1Char(
' ');
4495 secs -= (days * 86400);
4497 int hours = secs / 3600;
4499 tmp += i18np(
"1 hour",
"%1 hours", hours);
4500 tmp += QLatin1Char(
' ');
4501 secs -= (hours * 3600);
4503 int mins = secs / 60;
4505 tmp += i18np(
"1 minute",
"%1 minutes", mins);
4513 if (incidence->type() == Incidence::TypeEvent) {
4515 if (event->hasEndDate()) {
4516 if (!event->allDay()) {
4517 tmp = secs2Duration(event->dtStart().secsTo(event->dtEnd()));
4519 tmp = i18np(
"1 day",
"%1 days",
4520 event->dtStart().date().daysTo(event->dtEnd().date()) + 1);
4523 tmp = i18n(
"forever");
4525 }
else if (incidence->type() == Incidence::TypeTodo) {
4527 if (todo->hasDueDate()) {
4528 if (todo->hasStartDate()) {
4529 if (!todo->allDay()) {
4530 tmp = secs2Duration(todo->dtStart().secsTo(todo->dtDue()));
4532 tmp = i18np(
"1 day",
"%1 days",
4533 todo->dtStart().date().daysTo(todo->dtDue().date()) + 1);
4551 Alarm::List::ConstIterator it;
4552 for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) {
4555 QString remStr, atStr, offsetStr;
4556 if (alarm->hasTime()) {
4558 if (alarm->time().isValid()) {
4559 atStr = KGlobal::locale()->formatDateTime(alarm->time());
4561 }
else if (alarm->hasStartOffset()) {
4562 offset = alarm->startOffset().asSeconds();
4565 offsetStr = i18nc(
"N days/hours/minutes before the start datetime",
4566 "%1 before the start", secs2Duration(offset));
4567 }
else if (offset > 0) {
4568 offsetStr = i18nc(
"N days/hours/minutes after the start datetime",
4569 "%1 after the start", secs2Duration(offset));
4571 if (incidence->dtStart().isValid()) {
4572 atStr = KGlobal::locale()->formatDateTime(incidence->dtStart());
4575 }
else if (alarm->hasEndOffset()) {
4576 offset = alarm->endOffset().asSeconds();
4579 if (incidence->type() == Incidence::TypeTodo) {
4580 offsetStr = i18nc(
"N days/hours/minutes before the due datetime",
4581 "%1 before the to-do is due", secs2Duration(offset));
4583 offsetStr = i18nc(
"N days/hours/minutes before the end datetime",
4584 "%1 before the end", secs2Duration(offset));
4586 }
else if (offset > 0) {
4587 if (incidence->type() == Incidence::TypeTodo) {
4588 offsetStr = i18nc(
"N days/hours/minutes after the due datetime",
4589 "%1 after the to-do is due", secs2Duration(offset));
4591 offsetStr = i18nc(
"N days/hours/minutes after the end datetime",
4592 "%1 after the end", secs2Duration(offset));
4595 if (incidence->type() == Incidence::TypeTodo) {
4597 if (t->dtDue().isValid()) {
4598 atStr = KGlobal::locale()->formatDateTime(t->dtDue());
4602 if (e->dtEnd().isValid()) {
4603 atStr = KGlobal::locale()->formatDateTime(e->dtEnd());
4609 if (!atStr.isEmpty()) {
4610 remStr = i18nc(
"reminder occurs at datetime",
"at %1", atStr);
4616 if (alarm->repeatCount() > 0) {
4617 QString countStr = i18np(
"repeats once",
"repeats %1 times", alarm->repeatCount());
4618 QString intervalStr = i18nc(
"interval is N days/hours/minutes",
4620 secs2Duration(alarm->snoozeTime().asSeconds()));
4621 QString repeatStr = i18nc(
"(repeat string, interval string)",
4622 "(%1, %2)", countStr, intervalStr);
4623 remStr = remStr + QLatin1Char(
' ') + repeatStr;
QSharedPointer< Alarm > Ptr
QSharedPointer< Attachment > Ptr
QSharedPointer< Attendee > Ptr
QSharedPointer< Calendar > Ptr
QSharedPointer< Event > Ptr
QSharedPointer< FreeBusy > Ptr
virtual KDateTime dtStart() const
QSharedPointer< IncidenceBase > Ptr
virtual bool accept(Visitor &v, IncidenceBase::Ptr incidence)
QSharedPointer< Incidence > Ptr
QSharedPointer< Journal > Ptr
QSharedPointer< MemoryCalendar > Ptr
Duration duration() const
QSharedPointer< Person > Ptr
static Person::Ptr fromFullName(const QString &fullName)
ushort recurrenceType() const
QList< RecurrenceRule::WDayPos > yearPositions() const
QList< int > yearDates() const
QList< int > monthDays() const
KDateTime endDateTime() const
QList< int > yearMonths() const
QList< int > yearDays() const
QList< RecurrenceRule::WDayPos > monthPositions() const
QSharedPointer< ScheduleMessage > Ptr
QSharedPointer< Todo > Ptr
virtual bool visit(Event::Ptr event)
KCALUTILS_EXPORT QString mimeType()
Mime-type of iCalendar.
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.
KCALUTILS_EXPORT QString errorMessage(const KCalCore::Exception &exception)
Build a translated message representing an exception.
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 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...
This file is part of the API for handling calendar data and provides static functions for formatting ...