45 #include <kcalcore/visitor.h>
46 using namespace KCalCore;
48 #include <kpimidentities/identitymanager.h>
50 #include <kpimutils/email.h>
51 #include <kpimutils/linklocator.h>
53 #include <KCalendarSystem>
55 #include <KIconLoader>
56 #include <KLocalizedString>
59 #include <KSystemTimeZone>
61 #include <QtCore/QBitArray>
62 #include <QApplication>
64 #include <QTextDocument>
66 using namespace KCalUtils;
67 using namespace IncidenceFormatter;
78 return KPIMUtils::LinkLocator::convertToHtml(str);
81 static KPIMIdentities::IdentityManager *s_identityManager = 0;
85 struct RAIIIdentityManager{
89 s_identityManager =
new KPIMIdentities::IdentityManager(
true);
92 ~RAIIIdentityManager()
94 delete s_identityManager;
95 s_identityManager = 0;
101 static bool thatIsMe(
const QString &email)
103 return s_identityManager ? s_identityManager->thatIsMe(email)
104 : KPIMIdentities::IdentityManager(
true).thatIsMe(email);
110 return thatIsMe(attendee->email());
113 static bool iamPerson(
const Person &person)
116 return thatIsMe(person.
email());
134 Person person(name, email);
135 if (!iamPerson(person)) {
142 mailto.setPath(path);
145 static const QString iconPath =
146 KIconLoader::global()->iconPath(
QLatin1String(
"mail-message-new"), KIconLoader::Small);
175 if (numLineBreaks >= 0) {
176 if (numLineBreaks > 0) {
179 for (
int i = 0; i <= numLineBreaks; ++i) {
181 tmp = tmpText.
left(pos);
182 tmpText = tmpText.
right(tmpText.
length() - pos - 1);
214 static bool iamOrganizer(Incidence::Ptr incidence)
222 return thatIsMe(incidence->organizer()->email());
225 static bool senderIsOrganizer(Incidence::Ptr incidence,
const QString &sender)
229 if (!incidence || sender.
isEmpty()) {
234 QString senderName, senderEmail;
235 if (KPIMUtils::extractEmailAddressAndName(sender, senderEmail, senderName)) {
237 if (incidence->organizer()->email() != senderEmail &&
238 incidence->organizer()->name() != senderName) {
245 static bool attendeeIsOrganizer(
const Incidence::Ptr &incidence,
const Attendee::Ptr &attendee)
247 if (incidence && attendee &&
248 (incidence->organizer()->email() == attendee->email())) {
255 static QString organizerName(
const Incidence::Ptr incidence,
const QString &defName)
261 tName = i18n(
"Organizer Unknown");
266 name = incidence->organizer()->name();
268 name = incidence->organizer()->email();
277 static QString firstAttendeeName(
const Incidence::Ptr &incidence,
const QString &defName)
283 tName = i18n(
"Sender");
289 if (attendees.
count() > 0) {
291 name = attendee->name();
293 name = attendee->email();
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);
345 const QString printName = s.first;
346 const QString printUid = s.second;
355 personString += htmlAddUidLink(email, printName, printUid);
358 personString += (printName.
isEmpty() ? email : printName);
361 #ifndef KDEPIM_MOBILE_UI
364 personString +=
QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
374 return displayViewFormatPerson(email, name, uid, rsvpStatusIconPath(status));
377 static bool incOrganizerOwnsCalendar(
const Calendar::Ptr &calendar,
378 const Incidence::Ptr &incidence)
384 return iamOrganizer(incidence);
387 static 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();
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());
448 int attendeeCount = incidence->attendees().
count();
449 if (attendeeCount > 1 ||
450 (attendeeCount == 1 &&
451 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
454 incidence->organizer()->name(),
459 KIconLoader::global()->iconPath(
QLatin1String(
"meeting-organizer"), KIconLoader::Small);
460 tmpStr +=
QLatin1String(
"<td>") + displayViewFormatPerson(incidence->organizer()->email(),
461 s.first, s.second, iconPath) +
468 bool showStatus = incOrganizerOwnsCalendar(calendar, incidence);
471 str = displayViewFormatAttendeeRoleList(incidence,
Attendee::Chair, showStatus);
509 static QString displayViewFormatAttachments(Incidence::Ptr incidence)
517 if ((*it)->isUri()) {
520 name = i18n(
"Show mail");
522 if ((*it)->label().isEmpty()) {
525 name = (*it)->label();
528 tmpStr += htmlAddLink((*it)->uri(), name);
534 if (count < as.
count()) {
541 static QString displayViewFormatCategories(Incidence::Ptr incidence)
547 static 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));
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());
573 static QString displayViewFormatHeader(Incidence::Ptr incidence)
578 KIconLoader *iconLoader = KIconLoader::global();
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);
591 if (incidence->hasEnabledAlarms()) {
593 iconLoader->iconPath(
QLatin1String(
"preferences-desktop-notification-bell"), KIconLoader::Small) +
596 if (incidence->recurs()) {
598 iconLoader->iconPath(
QLatin1String(
"edit-redo"), KIconLoader::Small) +
601 if (incidence->isReadOnly()) {
603 iconLoader->iconPath(
QLatin1String(
"object-locked"), KIconLoader::Small) +
619 const QDate &date, KDateTime::Spec spec)
625 QString tmpStr = displayViewFormatHeader(event);
639 if (!event->location().isEmpty()) {
646 KDateTime startDt =
event->dtStart();
647 KDateTime endDt =
event->dtEnd();
648 if (event->recurs()) {
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()));
665 if (event->allDay()) {
666 if (event->isMultiDay()) {
669 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
676 i18nc(
"date as string",
"%1",
681 if (event->isMultiDay()) {
684 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
691 i18nc(
"date as string",
"%1",
697 if (event->hasEndDate() && startDt != endDt) {
699 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
720 if (event->recurs() ||
event->hasRecurrenceId()) {
725 if (event->hasRecurrenceId()) {
726 str = i18n(
"Exception");
736 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY") ==
QLatin1String(
"YES");
737 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY") ==
QLatin1String(
"YES");
739 if (isBirthday || isAnniversary) {
752 tmpStr += displayViewFormatDescription(event);
756 int reminderCount =
event->alarms().count();
757 if (reminderCount > 0 && event->hasEnabledAlarms()) {
760 i18np(
"Reminder:",
"Reminders:", reminderCount) +
766 tmpStr += displayViewFormatAttendees(calendar, event);
768 int categoryCount =
event->categories().count();
769 if (categoryCount > 0) {
772 tmpStr += i18np(
"Category:",
"Categories:", categoryCount) +
778 int attachmentCount =
event->attachments().count();
779 if (attachmentCount > 0) {
782 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
796 const QDate &ocurrenceDueDate, KDateTime::Spec spec)
799 kDebug() <<
"IncidenceFormatter::displayViewFormatTodo was called without to-do, quitting";
803 QString tmpStr = displayViewFormatHeader(todo);
817 if (!todo->location().isEmpty()) {
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);
846 i18nc(
"to-do start date/time",
"Start:") +
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());
865 i18nc(
"to-do due date/time",
"Due:") +
881 if (todo->recurs() || todo->hasRecurrenceId()) {
885 if (todo->hasRecurrenceId()) {
886 str = i18n(
"Exception");
896 tmpStr += displayViewFormatDescription(todo);
900 int reminderCount = todo->alarms().count();
901 if (reminderCount > 0 && todo->hasEnabledAlarms()) {
904 i18np(
"Reminder:",
"Reminders:", reminderCount) +
910 tmpStr += displayViewFormatAttendees(calendar, todo);
912 int categoryCount = todo->categories().count();
913 if (categoryCount > 0) {
916 i18np(
"Category:",
"Categories:", categoryCount) +
922 if (todo->priority() > 0) {
932 if (todo->isCompleted()) {
939 tmpStr += i18n(
"%1%", todo->percentComplete());
944 int attachmentCount = todo->attachments().count();
945 if (attachmentCount > 0) {
948 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
967 QString tmpStr = displayViewFormatHeader(journal);
988 tmpStr += displayViewFormatDescription(journal);
990 int categoryCount = journal->categories().count();
991 if (categoryCount > 0) {
994 i18np(
"Category:",
"Categories:", categoryCount) +
1011 Q_UNUSED(sourceName);
1018 QLatin1String(
"h2"), i18n(
"Free/Busy information for %1", fb->organizer()->fullName())));
1021 i18n(
"Busy times in date range %1 - %2:",
1027 htmlAddTag(
QLatin1String(
"b"), i18nc(
"tag for busy periods list",
"Busy:")));
1029 Period::List periods = fb->busyPeriods();
1030 Period::List::iterator it;
1031 for (it = periods.begin(); it != periods.end(); ++it) {
1033 if (per.hasDuration()) {
1034 int dur = per.duration().asSeconds();
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",
1052 if (per.start().date() == per.end().date()) {
1053 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1058 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1071 class KCalUtils::IncidenceFormatter::EventViewerVisitor :
public Visitor
1074 EventViewerVisitor()
1075 : mCalendar(0), mSpec(KDateTime::Spec()), mResult(
QLatin1String(
"")) {}
1077 bool act(
const Calendar::Ptr &calendar, IncidenceBase::Ptr incidence,
const QDate &date,
1078 KDateTime::Spec spec=KDateTime::Spec())
1080 mCalendar = calendar;
1081 mSourceName.
clear();
1085 return incidence->accept(*
this, incidence);
1088 bool act(
const QString &sourceName, IncidenceBase::Ptr incidence,
const QDate &date,
1089 KDateTime::Spec spec=KDateTime::Spec())
1091 mSourceName = sourceName;
1095 return incidence->accept(*
this, incidence);
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();
1128 KDateTime::Spec mSpec;
1134 const IncidenceBase::Ptr &incidence,
1136 KDateTime::Spec spec)
1142 EventViewerVisitor v;
1143 if (v.act(calendar, incidence, date, spec)) {
1151 const IncidenceBase::Ptr &incidence,
1153 KDateTime::Spec spec)
1159 EventViewerVisitor v;
1160 if (v.act(sourceName, incidence, date, spec)) {
1180 static 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);
1196 static 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);
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()));
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()));
1242 static QString htmlInvitationDetailsBegin()
1248 static QString htmlInvitationDetailsEnd()
1253 static QString htmlInvitationDetailsTableBegin()
1255 return QLatin1String(
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">");
1258 static QString htmlInvitationDetailsTableEnd()
1274 return qApp->palette().color(QPalette::Active, QPalette::Highlight).name();
1294 if (oldvalue.
isEmpty() || value == oldvalue) {
1295 return htmlRow(title, value);
1304 return htmlRow(newtitle, newvalue);
1307 static Attendee::Ptr findDelegatedFromMyAttendee(
const Incidence::Ptr &incidence)
1316 RAIIIdentityManager raiiHelper;
1317 QString delegatorName, delegatorEmail;
1322 KPIMUtils::extractEmailAddressAndName(a->delegator(), delegatorEmail, delegatorName);
1323 if (thatIsMe(delegatorEmail)) {
1332 static Attendee::Ptr findMyAttendee(
const Incidence::Ptr &incidence)
1341 RAIIIdentityManager raiiHelper;
1346 if (thatIsMe(a->email())) {
1355 static Attendee::Ptr findAttendee(
const Incidence::Ptr &incidence,
1365 RAIIIdentityManager raiiHelper;
1370 if (email == a->email()) {
1378 static bool rsvpRequested(
const Incidence::Ptr &incidence)
1391 rsvp = (*it)->RSVP();
1393 if ((*it)->RSVP() != rsvp) {
1402 static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role)
1404 if (rsvpRequested) {
1406 return i18n(
"Your response is requested");
1408 return i18n(
"Your response as <b>%1</b> is requested", role);
1412 return i18n(
"No response is necessary");
1414 return i18n(
"No response as <b>%1</b> is necessary", role);
1419 static QString myStatusStr(Incidence::Ptr incidence)
1425 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1426 Stringify::attendeeStatus(a->status()));
1436 noteStr +=
QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1443 noteStr += htmlAddTag(tag, title);
1462 const QString printName = s.first;
1463 const QString printUid = s.second;
1468 personString = htmlAddUidLink(email, printName, printUid);
1471 personString = (printName.
isEmpty() ? email : printName);
1474 personString = i18nc(
"name (comment)",
"%1 (%2)", personString, comment);
1480 personString +=
QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
1484 return personString;
1487 static QString invitationDetailsIncidence(
const Incidence::Ptr &incidence,
bool noHtmlMode)
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]);
1518 foreach (
const QString &c, incidence->comments()) {
1522 comments << string2HTML(c);
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);
1553 html +=
QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1563 html +=
QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1568 if (comments.
count() > 1) {
1570 for (
int i=0; i < comments.
count(); ++i) {
1575 html += comments[0];
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:"),
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);
1654 html += invitationNote(
QString(),
1655 i18n(
"Please respond again to the original proposal."),
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:"),
1676 if (!event->allDay()) {
1681 if (!oldevent->allDay()) {
1682 oldspanStr =
timeToString(oldevent->dtStart(),
true, spec) +
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:"),
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();
1739 static 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);
1802 html += invitationNote(
QString(),
1803 i18n(
"Please respond again to the original proposal."),
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();
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();
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();
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");
1942 Period::List periods = fb->busyPeriods();
1943 Period::List::iterator it;
1944 for (it = periods.begin(); it != periods.end(); ++it) {
1946 if (per.hasDuration()) {
1947 int dur = per.duration().asSeconds();
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);
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",
1969 KGlobal::locale()->
formatDate(per.start().date()),
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);
1995 static bool replyMeansCounter(
const Incidence::Ptr &incidence)
1997 Q_UNUSED(incidence);
2016 const Incidence::Ptr &existingIncidence,
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);
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) {
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);
2116 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2118 delegate = attendee->delegate();
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";
2157 const Incidence::Ptr &existingIncidence,
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);
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) {
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);
2267 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2269 delegate = attendee->delegate();
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";
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";
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";
2404 static QString invitationAttendeeList(
const Incidence::Ptr &incidence)
2406 RAIIIdentityManager raiiHelper;
2412 if (incidence->type() == Incidence::TypeTodo) {
2413 tmpStr += i18n(
"Assignees");
2415 tmpStr += i18n(
"Invitation List");
2425 if (!iamAttendee(a)) {
2428 tmpStr +=
QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
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());
2457 static QString invitationRsvpList(
const Incidence::Ptr &incidence,
const Attendee::Ptr &sender)
2463 if (incidence->type() == Incidence::TypeTodo) {
2464 tmpStr += i18n(
"Assignees");
2466 tmpStr += i18n(
"Invitation List");
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\">");
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());
2519 static QString invitationAttachments(InvitationFormatterHelper *helper,
2520 const Incidence::Ptr &incidence)
2527 if (incidence->type() == Incidence::TypeFreeBusy) {
2534 tmpStr += i18n(
"Attached Documents:") +
QLatin1String(
"<ol>");
2541 KMimeType::Ptr
mimeType = KMimeType::mimeType(a->mimeType());
2542 const QString iconStr = (mimeType ?
2543 mimeType->iconName(a->uri()) :
2545 const QString iconPath = KIconLoader::global()->iconPath(iconStr, KIconLoader::Small);
2559 class KCalUtils::IncidenceFormatter::ScheduleMessageVisitor :
public Visitor
2562 ScheduleMessageVisitor() : mMessage(0) {
2565 bool act(
const IncidenceBase::Ptr &incidence,
2566 const Incidence::Ptr &existingIncidence,
2569 mExistingIncidence = existingIncidence;
2572 return incidence->accept(*
this, incidence);
2580 Incidence::Ptr mExistingIncidence;
2585 class 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();
2611 class 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;
2649 InvitationFormatterHelper::InvitationFormatterHelper()
2654 InvitationFormatterHelper::~InvitationFormatterHelper()
2658 QString InvitationFormatterHelper::generateLinkURL(
const QString &
id)
2664 class IncidenceFormatter::IncidenceCompareVisitor :
public Visitor
2667 IncidenceCompareVisitor() {}
2668 bool act(
const IncidenceBase::Ptr &incidence,
2669 const Incidence::Ptr &existingIncidence)
2671 if (!existingIncidence) {
2674 Incidence::Ptr inc = incidence.staticCast<
Incidence>();
2675 if (!inc || !existingIncidence ||
2676 inc->revision() <= existingIncidence->revision()) {
2679 mExistingIncidence = existingIncidence;
2680 return incidence->
accept(*
this, incidence);
2685 if (mChanges.isEmpty()) {
2698 compareIncidences(event, mExistingIncidence);
2699 return !mChanges.isEmpty();
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",
2784 void compareIncidences(
const Incidence::Ptr &newInc,
2785 const Incidence::Ptr &oldInc)
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());
2833 Incidence::Ptr mExistingIncidence;
2842 arg(generateLinkURL(
id), text);
2847 arg(generateLinkURL(
id), text);
2854 static bool incidenceOwnedByMe(
const Calendar::Ptr &calendar,
2855 const Incidence::Ptr &incidence)
2858 Q_UNUSED(incidence);
2862 static QString inviteButton(InvitationFormatterHelper *helper,
2870 html +=
QLatin1String(
"<td style=\"border-width:2px;border-style:outset\">");
2871 if (!
id.isEmpty()) {
2872 html += helper->makeLink(
id, text);
2880 static QString inviteLink(InvitationFormatterHelper *helper,
2885 if (helper && !
id.isEmpty()) {
2886 html += helper->makeLink(
id, text);
2893 static QString responseButtons(
const Incidence::Ptr &incidence,
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"));
2913 i18nc(
"accept invitation",
"Accept"));
2916 html += inviteButton(helper,
QLatin1String(
"accept_conditionally"),
2917 i18nc(
"Accept invitation conditionally",
"Accept cond."));
2921 i18nc(
"invitation counter proposal",
"Counter proposal"));
2925 i18nc(
"decline invitation",
"Decline"));
2928 if (!rsvpRec || (incidence && incidence->revision() > 0)) {
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"));
2945 static QString counterButtons(
const Incidence::Ptr &incidence,
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"));
2970 static QString recordButtons(
const Incidence::Ptr &incidence,
2971 InvitationFormatterHelper *helper)
2979 if (incidence->type() == Incidence::TypeTodo) {
2981 i18n(
"Record invitation in my to-do list"));
2984 i18n(
"Record invitation in my calendar"));
2990 static QString recordResponseButtons(
const Incidence::Ptr &incidence,
2991 InvitationFormatterHelper *helper)
2999 if (incidence->type() == Incidence::TypeTodo) {
3001 i18n(
"Record response in my to-do list"));
3004 i18n(
"Record response in my calendar"));
3010 static QString cancelButtons(
const Incidence::Ptr &incidence,
3011 InvitationFormatterHelper *helper)
3020 if (incidence->type() == Incidence::TypeTodo) {
3022 i18n(
"Remove invitation from my to-do list"));
3025 i18n(
"Remove invitation from my calendar"));
3038 InvitationFormatterHelper *helper,
3040 KDateTime::Spec spec,
3042 bool outlookCompareStyle)
3054 kDebug() <<
"Failed to parse the scheduling message";
3060 IncidenceBase::Ptr incBase = msg->event();
3062 incBase->shiftTimes(mCalendar->timeSpec(), KDateTime::Spec::LocalZone());
3065 Incidence::Ptr existingIncidence;
3066 if (incBase && helper->calendar()) {
3067 existingIncidence = helper->calendar()->incidence(incBase->uid());
3069 if (!incidenceOwnedByMe(helper->calendar(), existingIncidence)) {
3070 existingIncidence.
clear();
3072 if (!existingIncidence) {
3073 const Incidence::List list = helper->calendar()->incidences();
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;
3084 Incidence::Ptr inc = incBase.staticCast<
Incidence>();
3088 int incRevision = 0;
3089 if (inc && inc->type() != Incidence::TypeFreeBusy) {
3090 incRevision = inc->revision();
3096 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
3098 if (!headerVisitor.act(inc, existingIncidence, msg, sender)) {
3101 html += htmlAddTag(
QLatin1String(
"h3"), headerVisitor.result());
3103 if (outlookCompareStyle ||
3106 IncidenceFormatter::InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3110 if (inc && existingIncidence &&
3111 incRevision < existingIncidence->revision()) {
3112 bodyOk = bodyVisitor.act(existingIncidence, inc, msg, sender);
3114 bodyOk = bodyVisitor.act(inc, existingIncidence, msg, sender);
3117 bodyOk = bodyVisitor.act(inc, Incidence::Ptr(), msg, sender);
3120 html += bodyVisitor.result();
3126 InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3127 if (!bodyVisitor.act(inc, Incidence::Ptr(), msg, sender)) {
3130 html += bodyVisitor.result();
3133 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
3134 if (compareVisitor.act(inc, existingIncidence)) {
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:");
3144 html += compareVisitor.result();
3148 IncidenceCompareVisitor compareVisitor;
3149 if (compareVisitor.act(inc, existingIncidence)) {
3152 html += i18n(
"The following changes have been made by %1:", sender);
3154 html += i18n(
"The following changes have been made by an attendee:");
3157 html += compareVisitor.result();
3163 bool myInc = iamOrganizer(inc);
3166 bool rsvpRec =
false;
3169 Incidence::Ptr rsvpIncidence = existingIncidence;
3170 if (!rsvpIncidence && inc && incRevision > 0) {
3171 rsvpIncidence = inc;
3173 if (rsvpIncidence) {
3174 ea = findMyAttendee(rsvpIncidence);
3177 (ea->status() == Attendee::Accepted ||
3178 ea->status() == Attendee::Declined ||
3179 ea->status() == Attendee::Tentative)) {
3186 bool isDelegated =
false;
3189 if (!inc->attendees().isEmpty()) {
3190 a = inc->attendees().first();
3194 isDelegated = (a->status() == Attendee::Delegated);
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()));
3212 tStr = i18n(
"This invitation was canceled");
3213 }
else if (msg->method() ==
iTIPAdd) {
3214 tStr = i18n(
"This invitation was accepted");
3217 tStr = rsvpRequestedStr(rsvpReq, role);
3220 tStr = rsvpRequestedStr(rsvpReq, role);
3222 tStr = i18n(
"Awaiting delegation response");
3231 if (inc && incRevision == 0) {
3232 QString statStr = myStatusStr(inc);
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)) {
3286 a = findDelegatedFromMyAttendee(inc);
3288 if (a->status() != Attendee::Accepted ||
3289 a->status() != Attendee::Tentative) {
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());
3303 if (ea && (ea->status() != Attendee::NeedsAction) && (ea->status() == a->status())) {
3304 const QString tStr = i18n(
"The <b>%1</b> response has been recorded",
3305 Stringify::attendeeStatus(ea->status()));
3309 html += recordResponseButtons(inc, helper);
3317 html += counterButtons(inc, helper);
3321 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3333 html += invitationRsvpList(existingIncidence, a);
3335 html += invitationAttendeeList(inc);
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,
3362 bool outlookCompareStyle)
3364 return formatICalInvitationHelper(invitation, calendar, helper,
true,
3365 KSystemTimeZones::local(), sender,
3366 outlookCompareStyle);
3374 class KCalUtils::IncidenceFormatter::ToolTipVisitor :
public Visitor
3378 : mRichText(true), mSpec(KDateTime::Spec()), mResult(
QLatin1String(
"")) {}
3381 const IncidenceBase::Ptr &incidence,
3382 const QDate &date=
QDate(),
bool richText=
true,
3383 KDateTime::Spec spec=KDateTime::Spec())
3385 mCalendar = calendar;
3388 mRichText = richText;
3391 return incidence ? incidence->accept(*
this, incidence) :
false;
3394 bool act(
const QString &location,
const IncidenceBase::Ptr &incidence,
3395 const QDate &date=
QDate(),
bool richText=
true,
3396 KDateTime::Spec spec=KDateTime::Spec())
3398 mLocation = location;
3400 mRichText = richText;
3403 return incidence ? incidence->accept(*
this, incidence) :
false;
3421 QString generateToolTip(
const Incidence::Ptr &incidence,
QString dtRangeText);
3428 KDateTime::Spec mSpec;
3432 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Event::Ptr &event,
3439 KDateTime startDt =
event->dtStart();
3440 KDateTime endDt =
event->dtEnd();
3441 if (event->recurs()) {
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);
3467 i18n(
"<i>Date:</i> %1",
dateToString(startDt,
false, mSpec));
3468 if (!event->allDay()) {
3471 if (dtStartTime == dtEndTime) {
3474 i18nc(
"time for event",
"<i>Time:</i> %1",
3478 i18nc(
"time range for event",
3479 "<i>Time:</i> %1 - %2",
3480 dtStartTime, dtEndTime);
3488 QString 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);
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());
3510 i18n(
"<i>Due:</i> %1",
3516 if (todo->priority() > 0) {
3523 if (todo->isCompleted()) {
3528 ret += i18n(
"%1%", todo->percentComplete());
3538 if (journal->dtStart().isValid()) {
3540 i18n(
"<i>Date:</i> %1",
dateToString(journal->dtStart(),
false, mSpec));
3550 i18n(
"<i>Period start:</i> %1",
3553 i18n(
"<i>Period start:</i> %1",
3560 mResult = generateToolTip(event, dateRangeText(event, mDate));
3561 return !mResult.isEmpty();
3566 mResult = generateToolTip(todo, dateRangeText(todo, mDate));
3567 return !mResult.isEmpty();
3572 mResult = generateToolTip(journal, dateRangeText(journal));
3573 return !mResult.isEmpty();
3580 i18n(
"Free/Busy information for %1", fb->organizer()->fullName()) +
3582 mResult += dateRangeText(fb);
3584 return !mResult.isEmpty();
3590 const QString printName = searchName(email, name);
3593 const QString iconPath = rsvpStatusIconPath(status);
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;
3613 const QString printName = searchName(email, name);
3617 KIconLoader::global()->iconPath(
QLatin1String(
"meeting-organizer"), KIconLoader::Small);
3622 personString += (printName.
isEmpty() ? email : printName);
3623 return personString;
3626 static QString tooltipFormatAttendeeRoleList(
const Incidence::Ptr &incidence,
3630 const QString etc = i18nc(
"elipsis",
"...");
3634 Attendee::List::ConstIterator it;
3639 if (a->role() != role) {
3643 if (attendeeIsOrganizer(incidence, a)) {
3647 if (i == maxNumAtts) {
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());
3669 const Incidence::Ptr &incidence)
3674 int attendeeCount = incidence->attendees().
count();
3675 if (attendeeCount > 1 ||
3676 (attendeeCount == 1 &&
3677 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
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);
3695 str = tooltipFormatAttendeeRoleList(incidence, Attendee::ReqParticipant, showStatus);
3702 str = tooltipFormatAttendeeRoleList(incidence, Attendee::OptParticipant, showStatus);
3709 str = tooltipFormatAttendeeRoleList(incidence, Attendee::NonParticipant, showStatus);
3718 QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
const Incidence::Ptr &incidence,
3721 int maxDescLen = 120;
3745 if (!incidence->location().isEmpty()) {
3748 tmp += incidence->richLocation();
3758 if (incidence->recurs()) {
3764 if (incidence->hasRecurrenceId()) {
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",
"...");
3786 int reminderCount = incidence->alarms().count();
3787 if (reminderCount > 0 && incidence->hasEnabledAlarms()) {
3794 tmp += tooltipFormatAttendees(mCalendar, incidence);
3796 int categoryCount = incidence->categories().count();
3797 if (categoryCount > 0) {
3809 const IncidenceBase::Ptr &incidence,
3812 KDateTime::Spec spec)
3815 if (incidence && v.act(sourceName, incidence, date, richText, spec)) {
3827 static QString mailBodyIncidence(
const Incidence::Ptr &incidence)
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());
3844 class KCalUtils::IncidenceFormatter::MailBodyVisitor :
public Visitor
3850 bool act(IncidenceBase::Ptr incidence, KDateTime::Spec spec=KDateTime::Spec())
3854 return incidence ? incidence->accept(*
this, incidence) :
false;
3867 mResult = i18n(
"This is a Free Busy Object");
3868 return !mResult.isEmpty();
3871 KDateTime::Spec mSpec;
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());
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();
3936 mResult += i18n(
"Details:\n%1\n", descStr);
3939 return !mResult.isEmpty();
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();
3960 mResult += i18n(
"Details:\n%1\n", details);
3962 return !mResult.isEmpty();
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)) {
3994 static QString recurEnd(
const Incidence::Ptr &incidence)
3997 if (incidence->allDay()) {
3998 endstr = KGlobal::locale()->formatDate(incidence->recurrence()->endDate());
4000 endstr = KGlobal::locale()->formatDateTime(incidence->recurrence()->endDateTime());
4012 if (incidence->hasRecurrenceId()) {
4016 if (!incidence->recurs()) {
4017 return i18n(
"No recurrence");
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();
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));
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",
4268 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4269 "Recurs yearly on %1 %2",
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),
4338 recurStr = i18n(
"Incidence recurs");
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);
4381 case Recurrence::rDaily:
4382 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4384 case Recurrence::rWeekly:
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);
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));
4481 const Incidence::Ptr &incidence)
4484 Q_UNUSED(incidence);
4488 static QString secs2Duration(
int secs)
4491 int days = secs / 86400;
4493 tmp += i18np(
"1 day",
"%1 days", days);
4495 secs -= (days * 86400);
4497 int hours = secs / 3600;
4499 tmp += i18np(
"1 hour",
"%1 hours", hours);
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;
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());
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);
4625 reminderStringList << remStr;
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString & append(QChar ch)
virtual bool visit(Event::Ptr event)
const_iterator constEnd() const
QString simplified() const
QList< int > yearDays() const
KCALUTILS_EXPORT QString formatDate(const KDateTime &dt, bool shortfmt=true, const KDateTime::Spec &spec=KDateTime::Spec())
Build a QString date representation of a KDateTime object.
QString join(const QString &separator) const
QList< int > yearDates() const
QString & remove(int position, int n)
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.
virtual bool accept(Visitor &v, IncidenceBase::Ptr incidence)
QString number(int n, int base)
int count(const T &value) const
void append(const T &value)
QString fromUtf8(const char *str, int size)
KCALUTILS_EXPORT QString mimeType()
Mime-type of iCalendar.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
This file is part of the API for handling calendar data and provides static functions for formatting ...
QList< int > monthDays() const
KCALUTILS_EXPORT QString errorMessage(const KCalCore::Exception &exception)
Build a translated message representing an exception.
QString right(int n) const
QList< int > yearMonths() const
static Person::Ptr fromFullName(const QString &fullName)
QString & replace(int position, int n, QChar after)
const_iterator constBegin() const
QSharedPointer< X > dynamicCast() const
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...
QString escape(const QString &plain)
int count(const T &value) const
bool mightBeRichText(const QString &text)
QString left(int n) const
QString fromLatin1(const char *str, int size)
ushort recurrenceType() const
QDate addDays(int ndays) const
const_iterator constEnd() const
const_iterator constBegin() const
QSharedPointer< X > staticCast() const
KDateTime endDateTime() const
bool testBit(int i) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QList< RecurrenceRule::WDayPos > monthPositions() const
QList< RecurrenceRule::WDayPos > yearPositions() const