45 #include <kcalcore/visitor.h>
46 using namespace KCalCore;
48 #include <kpimutils/email.h>
50 #include <KCalendarSystem>
52 #include <KEMailSettings>
53 #include <KIconLoader>
56 #include <KSystemTimeZone>
58 #include <QtCore/QBitArray>
59 #include <QtGui/QApplication>
60 #include <QtGui/QPalette>
61 #include <QtGui/QTextDocument>
63 using namespace KCalUtils;
64 using namespace IncidenceFormatter;
71 static QString htmlAddLink(
const QString &ref,
const QString &text,
74 QString tmpStr(
"<a href=\"" + ref +
"\">" + text +
"</a>" );
81 static QString htmlAddMailtoLink(
const QString &email,
const QString &name )
85 if ( !email.isEmpty() ) {
86 Person person( name, email );
87 QString path = person.fullName().simplified();
88 if ( path.isEmpty() || path.startsWith(
'"' ) ) {
92 mailto.setProtocol(
"mailto" );
93 mailto.setPath( path );
94 const QString iconPath =
95 KIconLoader::global()->iconPath(
"mail-message-new", KIconLoader::Small );
96 str = htmlAddLink( mailto.url(),
"<img valign=\"top\" src=\"" + iconPath +
"\">" );
101 static QString htmlAddUidLink(
const QString &email,
const QString &name,
const QString &uid )
105 if ( !uid.isEmpty() ) {
107 if ( name.isEmpty() ) {
109 str += htmlAddLink(
"uid:" + uid, email );
111 str += htmlAddLink(
"uid:" + uid, name );
117 static QString htmlAddTag(
const QString &tag,
const QString &text )
119 int numLineBreaks = text.count(
"\n" );
120 QString str =
'<' + tag +
'>';
121 QString tmpText = text;
122 QString tmpStr = str;
123 if( numLineBreaks >= 0 ) {
124 if ( numLineBreaks > 0 ) {
127 for (
int i = 0; i <= numLineBreaks; ++i ) {
128 pos = tmpText.indexOf(
"\n" );
129 tmp = tmpText.left( pos );
130 tmpText = tmpText.right( tmpText.length() - pos - 1 );
131 tmpStr += tmp +
"<br>";
137 tmpStr +=
"</" + tag +
'>';
141 static QPair<QString, QString> searchNameAndUid(
const QString &email,
const QString &name,
147 QPair<QString, QString>s;
150 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
156 static QString searchName(
const QString &email,
const QString &name )
158 const QString printName = name.isEmpty() ? email : name;
167 KEMailSettings settings;
168 QStringList profiles = settings.profiles();
169 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
170 settings.setProfile( *it );
171 if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->email() ) {
188 KEMailSettings settings;
189 QStringList profiles = settings.profiles();
190 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
191 settings.setProfile( *it );
192 if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->organizer()->email() ) {
200 static bool senderIsOrganizer(
Incidence::Ptr incidence,
const QString &sender )
204 if ( !incidence || sender.isEmpty() ) {
209 QString senderName, senderEmail;
210 if ( KPIMUtils::extractEmailAddressAndName( sender, senderEmail, senderName ) ) {
212 if ( incidence->organizer()->email() != senderEmail &&
213 incidence->organizer()->name() != senderName ) {
222 if ( incidence && attendee &&
223 ( incidence->organizer()->email() == attendee->email() ) ) {
230 static QString organizerName(
const Incidence::Ptr incidence,
const QString &defName )
233 if ( !defName.isEmpty() ) {
236 tName = i18n(
"Organizer Unknown" );
241 name = incidence->organizer()->name();
242 if ( name.isEmpty() ) {
243 name = incidence->organizer()->email();
246 if ( name.isEmpty() ) {
252 static QString firstAttendeeName(
const Incidence::Ptr &incidence,
const QString &defName )
255 if ( !defName.isEmpty() ) {
258 tName = i18n(
"Sender" );
264 if( attendees.count() > 0 ) {
266 name = attendee->name();
267 if ( name.isEmpty() ) {
268 name = attendee->email();
272 if ( name.isEmpty() ) {
283 iconPath = KIconLoader::global()->iconPath(
"dialog-ok-apply", KIconLoader::Small );
286 iconPath = KIconLoader::global()->iconPath(
"dialog-cancel", KIconLoader::Small );
289 iconPath = KIconLoader::global()->iconPath(
"help-about", KIconLoader::Small );
292 iconPath = KIconLoader::global()->iconPath(
"help-about", KIconLoader::Small );
295 iconPath = KIconLoader::global()->iconPath(
"dialog-ok", KIconLoader::Small );
298 iconPath = KIconLoader::global()->iconPath(
"mail-forward", KIconLoader::Small );
301 iconPath = KIconLoader::global()->iconPath(
"mail-mark-read", KIconLoader::Small );
315 static QString displayViewFormatPerson(
const QString &email,
const QString &name,
316 const QString &uid,
const QString &iconPath )
319 QPair<QString, QString> s = searchNameAndUid( email, name, uid );
320 const QString printName = s.first;
321 const QString printUid = s.second;
323 QString personString;
324 if ( !iconPath.isEmpty() ) {
325 personString +=
"<img valign=\"top\" src=\"" + iconPath +
"\">" +
" ";
329 if ( !printUid.isEmpty() ) {
330 personString += htmlAddUidLink( email, printName, printUid );
333 personString += ( printName.isEmpty() ? email : printName );
336 #ifndef KDEPIM_MOBILE_UI
338 if ( !email.isEmpty() ) {
339 personString +=
" " + htmlAddMailtoLink( email, printName );
346 static QString displayViewFormatPerson(
const QString &email,
const QString &name,
349 return displayViewFormatPerson( email, name, uid, rsvpStatusIconPath( status ) );
352 static bool incOrganizerOwnsCalendar(
const Calendar::Ptr &calendar,
358 Q_UNUSED( calendar );
359 return iamOrganizer( incidence );
366 Attendee::List::ConstIterator it;
369 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
371 if ( a->role() != role ) {
375 if ( attendeeIsOrganizer( incidence, a ) ) {
379 tmpStr += displayViewFormatPerson( a->email(), a->name(), a->uid(),
380 showStatus ? a->status() : Attendee::None );
381 if ( !a->delegator().isEmpty() ) {
382 tmpStr += i18n(
" (delegated by %1)", a->delegator() );
384 if ( !a->delegate().isEmpty() ) {
385 tmpStr += i18n(
" (delegated to %1)", a->delegate() );
389 if ( tmpStr.endsWith( QLatin1String(
"<br>" ) ) ) {
400 int attendeeCount = incidence->attendees().count();
401 if ( attendeeCount > 1 ||
402 ( attendeeCount == 1 &&
403 !attendeeIsOrganizer( incidence, incidence->attendees().first() ) ) ) {
405 QPair<QString, QString> s = searchNameAndUid( incidence->organizer()->email(),
406 incidence->organizer()->name(),
409 tmpStr +=
"<td><b>" + i18n(
"Organizer:" ) +
"</b></td>";
410 const QString iconPath =
411 KIconLoader::global()->iconPath(
"meeting-organizer", KIconLoader::Small );
412 tmpStr +=
"<td>" + displayViewFormatPerson( incidence->organizer()->email(),
413 s.first, s.second, iconPath ) +
420 bool showStatus = incOrganizerOwnsCalendar( calendar, incidence );
423 str = displayViewFormatAttendeeRoleList( incidence,
Attendee::Chair, showStatus );
424 if ( !str.isEmpty() ) {
426 tmpStr +=
"<td><b>" + i18n(
"Chair:" ) +
"</b></td>";
427 tmpStr +=
"<td>" + str +
"</td>";
433 if ( !str.isEmpty() ) {
435 tmpStr +=
"<td><b>" + i18n(
"Required Participants:" ) +
"</b></td>";
436 tmpStr +=
"<td>" + str +
"</td>";
442 if ( !str.isEmpty() ) {
444 tmpStr +=
"<td><b>" + i18n(
"Optional Participants:" ) +
"</b></td>";
445 tmpStr +=
"<td>" + str +
"</td>";
451 if ( !str.isEmpty() ) {
453 tmpStr +=
"<td><b>" + i18n(
"Observers:" ) +
"</b></td>";
454 tmpStr +=
"<td>" + str +
"</td>";
461 static QString displayViewFormatAttachments(
Incidence::Ptr incidence )
465 Attachment::List::ConstIterator it;
467 for ( it = as.constBegin(); it != as.constEnd(); ++it ) {
469 if ( (*it)->isUri() ) {
471 if ( (*it)->uri().startsWith( QLatin1String(
"kmail:" ) ) ) {
472 name = i18n(
"Show mail" );
474 if ( (*it)->label().isEmpty() ) {
477 name = (*it)->label();
480 tmpStr += htmlAddLink( (*it)->uri(), name );
482 tmpStr += htmlAddLink( QString::fromLatin1(
"ATTACH:%1" ).
483 arg( QString::fromUtf8( (*it)->label().toUtf8().toBase64() ) ),
486 if ( count < as.count() ) {
493 static QString displayViewFormatCategories(
Incidence::Ptr incidence )
496 return incidence->categories().join(
", " );
499 static QString displayViewFormatCreationDate(
Incidence::Ptr incidence, KDateTime::Spec spec )
501 KDateTime kdt = incidence->created().toTimeSpec( spec );
502 return i18n(
"Creation date: %1",
dateTimeToString( incidence->created(),
false,
true, spec ) );
505 static QString displayViewFormatBirthday(
Event::Ptr event )
510 if ( event->customProperty(
"KABC",
"BIRTHDAY" ) !=
"YES" &&
511 event->customProperty(
"KABC",
"ANNIVERSARY" ) !=
"YES" ) {
515 QString uid_1 =
event->customProperty(
"KABC",
"UID-1" );
516 QString name_1 =
event->customProperty(
"KABC",
"NAME-1" );
517 QString email_1=
event->customProperty(
"KABC",
"EMAIL-1" );
519 QString tmpStr = displayViewFormatPerson( email_1, name_1, uid_1, QString() );
523 static QString displayViewFormatHeader(
Incidence::Ptr incidence )
525 QString tmpStr =
"<table><tr>";
528 KIconLoader *iconLoader = KIconLoader::global();
532 if ( incidence->customProperty(
"KABC",
"BIRTHDAY" ) ==
"YES" ) {
533 iconPath = iconLoader->iconPath(
"view-calendar-birthday", KIconLoader::Small );
534 }
else if ( incidence->customProperty(
"KABC",
"ANNIVERSARY" ) ==
"YES" ) {
535 iconPath = iconLoader->iconPath(
"view-calendar-wedding-anniversary", KIconLoader::Small );
537 iconPath = iconLoader->iconPath( incidence->iconName(), KIconLoader::Small );
539 tmpStr +=
"<img valign=\"top\" src=\"" + iconPath +
"\">";
541 if ( incidence->hasEnabledAlarms() ) {
542 tmpStr +=
"<img valign=\"top\" src=\"" +
543 iconLoader->iconPath(
"preferences-desktop-notification-bell", KIconLoader::Small ) +
546 if ( incidence->recurs() ) {
547 tmpStr +=
"<img valign=\"top\" src=\"" +
548 iconLoader->iconPath(
"edit-redo", KIconLoader::Small ) +
551 if ( incidence->isReadOnly() ) {
552 tmpStr +=
"<img valign=\"top\" src=\"" +
553 iconLoader->iconPath(
"object-locked", KIconLoader::Small ) +
559 tmpStr +=
"<b><u>" + incidence->richSummary() +
"</u></b>";
562 tmpStr +=
"</tr></table>";
567 static QString displayViewFormatEvent(
const Calendar::Ptr calendar,
const QString &sourceName,
569 const QDate &date, KDateTime::Spec spec )
575 QString tmpStr = displayViewFormatHeader( event );
578 tmpStr +=
"<col width=\"25%\"/>";
579 tmpStr +=
"<col width=\"75%\"/>";
581 const QString calStr = calendar ?
resourceString( calendar, event ) : sourceName;
582 if ( !calStr.isEmpty() ) {
584 tmpStr +=
"<td><b>" + i18n(
"Calendar:" ) +
"</b></td>";
585 tmpStr +=
"<td>" + calStr +
"</td>";
589 if ( !event->location().isEmpty() ) {
591 tmpStr +=
"<td><b>" + i18n(
"Location:" ) +
"</b></td>";
592 tmpStr +=
"<td>" +
event->richLocation() +
"</td>";
596 KDateTime startDt =
event->dtStart();
597 KDateTime endDt =
event->dtEnd();
598 if ( event->recurs() ) {
599 if ( date.isValid() ) {
600 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
601 int diffDays = startDt.daysTo( kdt );
602 kdt = kdt.addSecs( -1 );
603 startDt.setDate( event->recurrence()->getNextDateTime( kdt ).date() );
604 if ( event->hasEndDate() ) {
605 endDt = endDt.addDays( diffDays );
606 if ( startDt > endDt ) {
607 startDt.setDate( event->recurrence()->getPreviousDateTime( kdt ).date() );
608 endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
615 if ( event->allDay() ) {
616 if ( event->isMultiDay() ) {
617 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
619 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
624 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
626 i18nc(
"date as string",
"%1",
631 if ( event->isMultiDay() ) {
632 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
634 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
639 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
641 i18nc(
"date as string",
"%1",
645 tmpStr +=
"</tr><tr>";
646 tmpStr +=
"<td><b>" + i18n(
"Time:" ) +
"</b></td>";
647 if ( event->hasEndDate() && startDt != endDt ) {
649 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
663 if ( !durStr.isEmpty() ) {
665 tmpStr +=
"<td><b>" + i18n(
"Duration:" ) +
"</b></td>";
666 tmpStr +=
"<td>" + durStr +
"</td>";
670 if ( event->recurs() ) {
672 tmpStr +=
"<td><b>" + i18n(
"Recurrence:" ) +
"</b></td>";
679 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY" ) ==
"YES";
680 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY" ) ==
"YES";
682 if ( isBirthday || isAnniversary ) {
684 if ( isAnniversary ) {
685 tmpStr +=
"<td><b>" + i18n(
"Anniversary:" ) +
"</b></td>";
687 tmpStr +=
"<td><b>" + i18n(
"Birthday:" ) +
"</b></td>";
689 tmpStr +=
"<td>" + displayViewFormatBirthday( event ) +
"</td>";
691 tmpStr +=
"</table>";
695 if ( !event->description().isEmpty() ) {
697 tmpStr +=
"<td><b>" + i18n(
"Description:" ) +
"</b></td>";
698 tmpStr +=
"<td>" +
event->richDescription() +
"</td>";
704 int reminderCount =
event->alarms().count();
705 if ( reminderCount > 0 && event->hasEnabledAlarms() ) {
707 tmpStr +=
"<td><b>" +
708 i18np(
"Reminder:",
"Reminders:", reminderCount ) +
714 tmpStr += displayViewFormatAttendees( calendar, event );
716 int categoryCount =
event->categories().count();
717 if ( categoryCount > 0 ) {
720 tmpStr += i18np(
"Category:",
"Categories:", categoryCount ) +
722 tmpStr +=
"<td>" + displayViewFormatCategories( event ) +
"</td>";
726 int attachmentCount =
event->attachments().count();
727 if ( attachmentCount > 0 ) {
729 tmpStr +=
"<td><b>" +
730 i18np(
"Attachment:",
"Attachments:", attachmentCount ) +
732 tmpStr +=
"<td>" + displayViewFormatAttachments( event ) +
"</td>";
735 tmpStr +=
"</table>";
737 tmpStr +=
"<p><em>" + displayViewFormatCreationDate( event, spec ) +
"</em>";
742 static QString displayViewFormatTodo(
const Calendar::Ptr &calendar,
const QString &sourceName,
744 const QDate &date, KDateTime::Spec spec )
747 kDebug() <<
"IncidenceFormatter::displayViewFormatTodo was called without to-do, quitting";
751 QString tmpStr = displayViewFormatHeader( todo );
754 tmpStr +=
"<col width=\"25%\"/>";
755 tmpStr +=
"<col width=\"75%\"/>";
757 const QString calStr = calendar ?
resourceString( calendar, todo ) : sourceName;
758 if ( !calStr.isEmpty() ) {
760 tmpStr +=
"<td><b>" + i18n(
"Calendar:" ) +
"</b></td>";
761 tmpStr +=
"<td>" + calStr +
"</td>";
765 if ( !todo->location().isEmpty() ) {
767 tmpStr +=
"<td><b>" + i18n(
"Location:" ) +
"</b></td>";
768 tmpStr +=
"<td>" + todo->richLocation() +
"</td>";
772 const bool hastStartDate = todo->hasStartDate() && todo->dtStart().isValid();
773 const bool hasDueDate = todo->hasDueDate() && todo->dtDue().isValid();
775 if ( hastStartDate ) {
776 KDateTime startDt = todo->dtStart(
true );
777 if ( todo->recurs() ) {
778 if ( date.isValid() ) {
781 const int length = startDt.daysTo( todo->dtDue(
true ) );
783 startDt.setDate( date.addDays( -length ) );
785 kError() <<
"DTSTART is bigger than DTDUE, todo->uid() is " << todo->uid();
786 startDt.setDate( date );
789 kError() <<
"To-do is recurring but has no DTDUE set, todo->uid() is " << todo->uid();
790 startDt.setDate( date );
795 tmpStr +=
"<td><b>" +
796 i18nc(
"to-do start date/time",
"Start:" ) +
805 KDateTime dueDt = todo->dtDue();
806 if ( todo->recurs() ) {
807 if ( date.isValid() ) {
808 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
809 kdt = kdt.addSecs( -1 );
810 dueDt.setDate( todo->recurrence()->getNextDateTime( kdt ).date() );
814 tmpStr +=
"<td><b>" +
815 i18nc(
"to-do due date/time",
"Due:" ) +
824 if ( !durStr.isEmpty() ) {
826 tmpStr +=
"<td><b>" + i18n(
"Duration:" ) +
"</b></td>";
827 tmpStr +=
"<td>" + durStr +
"</td>";
831 if ( todo->recurs() ) {
833 tmpStr +=
"<td><b>" + i18n(
"Recurrence:" ) +
"</b></td>";
840 if ( !todo->description().isEmpty() ) {
842 tmpStr +=
"<td><b>" + i18n(
"Description:" ) +
"</b></td>";
843 tmpStr +=
"<td>" + todo->richDescription() +
"</td>";
849 int reminderCount = todo->alarms().count();
850 if ( reminderCount > 0 && todo->hasEnabledAlarms() ) {
852 tmpStr +=
"<td><b>" +
853 i18np(
"Reminder:",
"Reminders:", reminderCount ) +
859 tmpStr += displayViewFormatAttendees( calendar, todo );
861 int categoryCount = todo->categories().count();
862 if ( categoryCount > 0 ) {
864 tmpStr +=
"<td><b>" +
865 i18np(
"Category:",
"Categories:", categoryCount ) +
867 tmpStr +=
"<td>" + displayViewFormatCategories( todo ) +
"</td>";
871 if ( todo->priority() > 0 ) {
873 tmpStr +=
"<td><b>" + i18n(
"Priority:" ) +
"</b></td>";
875 tmpStr += QString::number( todo->priority() );
881 if ( todo->isCompleted() ) {
882 tmpStr +=
"<td><b>" + i18nc(
"Completed: date",
"Completed:" ) +
"</b></td>";
886 tmpStr +=
"<td><b>" + i18n(
"Percent Done:" ) +
"</b></td>";
888 tmpStr += i18n(
"%1%", todo->percentComplete() );
893 int attachmentCount = todo->attachments().count();
894 if ( attachmentCount > 0 ) {
896 tmpStr +=
"<td><b>" +
897 i18np(
"Attachment:",
"Attachments:", attachmentCount ) +
899 tmpStr +=
"<td>" + displayViewFormatAttachments( todo ) +
"</td>";
902 tmpStr +=
"</table>";
904 tmpStr +=
"<p><em>" + displayViewFormatCreationDate( todo, spec ) +
"</em>";
909 static QString displayViewFormatJournal(
const Calendar::Ptr &calendar,
const QString &sourceName,
916 QString tmpStr = displayViewFormatHeader( journal );
919 tmpStr +=
"<col width=\"25%\"/>";
920 tmpStr +=
"<col width=\"75%\"/>";
922 const QString calStr = calendar ?
resourceString( calendar, journal ) : sourceName;
923 if ( !calStr.isEmpty() ) {
925 tmpStr +=
"<td><b>" + i18n(
"Calendar:" ) +
"</b></td>";
926 tmpStr +=
"<td>" + calStr +
"</td>";
931 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
937 if ( !journal->description().isEmpty() ) {
939 tmpStr +=
"<td><b>" + i18n(
"Description:" ) +
"</b></td>";
940 tmpStr +=
"<td>" + journal->richDescription() +
"</td>";
944 int categoryCount = journal->categories().count();
945 if ( categoryCount > 0 ) {
947 tmpStr +=
"<td><b>" +
948 i18np(
"Category:",
"Categories:", categoryCount ) +
950 tmpStr +=
"<td>" + displayViewFormatCategories( journal ) +
"</td>";
954 tmpStr +=
"</table>";
956 tmpStr +=
"<p><em>" + displayViewFormatCreationDate( journal, spec ) +
"</em>";
961 static QString displayViewFormatFreeBusy(
const Calendar::Ptr &calendar,
const QString &sourceName,
964 Q_UNUSED( calendar );
965 Q_UNUSED( sourceName );
972 "h2", i18n(
"Free/Busy information for %1", fb->organizer()->fullName() ) ) );
974 tmpStr += htmlAddTag(
"h4",
975 i18n(
"Busy times in date range %1 - %2:",
981 htmlAddTag(
"b", i18nc(
"tag for busy periods list",
"Busy:" ) ) );
984 Period::List::iterator it;
985 for ( it = periods.begin(); it != periods.end(); ++it ) {
991 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600 );
995 cont += i18ncp(
"minutes part duration",
"1 minute ",
"%1 minutes ", dur / 60 );
999 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur );
1001 text += i18nc(
"startDate for duration",
"%1 for %2",
1006 if ( per.
start().date() == per.
end().date() ) {
1007 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1012 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1019 tmpStr += htmlAddTag(
"p", text );
1025 class KCalUtils::IncidenceFormatter::EventViewerVisitor :
public Visitor
1028 EventViewerVisitor()
1029 : mCalendar( 0 ), mSpec( KDateTime::Spec() ), mResult(
"" ) {}
1032 KDateTime::Spec spec=KDateTime::Spec() )
1034 mCalendar = calendar;
1035 mSourceName.clear();
1039 return incidence->accept( *
this, incidence );
1042 bool act(
const QString &sourceName,
IncidenceBase::Ptr incidence,
const QDate &date,
1043 KDateTime::Spec spec=KDateTime::Spec() )
1045 mSourceName = sourceName;
1049 return incidence->accept( *
this, incidence );
1052 QString result()
const {
return mResult; }
1057 mResult = displayViewFormatEvent( mCalendar, mSourceName, event, mDate, mSpec );
1058 return !mResult.isEmpty();
1062 mResult = displayViewFormatTodo( mCalendar, mSourceName, todo, mDate, mSpec );
1063 return !mResult.isEmpty();
1067 mResult = displayViewFormatJournal( mCalendar, mSourceName, journal, mSpec );
1068 return !mResult.isEmpty();
1072 mResult = displayViewFormatFreeBusy( mCalendar, mSourceName, fb, mSpec );
1073 return !mResult.isEmpty();
1078 QString mSourceName;
1080 KDateTime::Spec mSpec;
1088 KDateTime::Spec spec )
1094 EventViewerVisitor v;
1095 if ( v.act( calendar, incidence, date, spec ) ) {
1105 KDateTime::Spec spec )
1111 EventViewerVisitor v;
1112 if ( v.act( sourceName, incidence, date, spec ) ) {
1123 static QString string2HTML(
const QString &str )
1125 return Qt::convertFromPlainText( str, Qt::WhiteSpaceNormal );
1128 static QString cleanHtml(
const QString &html )
1130 QRegExp rx(
"<body[^>]*>(.*)</body>", Qt::CaseInsensitive );
1132 QString body = rx.cap( 1 );
1134 return Qt::escape( body.remove( QRegExp(
"<[^>]*>" ) ).trimmed() );
1137 static QString invitationSummary(
const Incidence::Ptr &incidence,
bool noHtmlMode )
1139 QString summaryStr = i18n(
"Summary unspecified" );
1140 if ( !incidence->summary().isEmpty() ) {
1141 if ( !incidence->summaryIsRich() ) {
1142 summaryStr = Qt::escape( incidence->summary() );
1144 summaryStr = incidence->richSummary();
1146 summaryStr = cleanHtml( summaryStr );
1153 static QString invitationLocation(
const Incidence::Ptr &incidence,
bool noHtmlMode )
1155 QString locationStr = i18n(
"Location unspecified" );
1156 if ( !incidence->location().isEmpty() ) {
1157 if ( !incidence->locationIsRich() ) {
1158 locationStr = Qt::escape( incidence->location() );
1160 locationStr = incidence->richLocation();
1162 locationStr = cleanHtml( locationStr );
1169 static QString eventStartTimeStr(
const Event::Ptr &event )
1172 if ( !event->allDay() ) {
1173 tmp = i18nc(
"%1: Start Date, %2: Start Time",
"%1 %2",
1174 dateToString( event->dtStart(),
true, KSystemTimeZones::local() ),
1175 timeToString( event->dtStart(),
true, KSystemTimeZones::local() ) );
1177 tmp = i18nc(
"%1: Start Date",
"%1 (all day)",
1178 dateToString( event->dtStart(),
true, KSystemTimeZones::local() ) );
1183 static QString eventEndTimeStr(
const Event::Ptr &event )
1186 if ( event->hasEndDate() &&
event->dtEnd().isValid() ) {
1187 if ( !event->allDay() ) {
1188 tmp = i18nc(
"%1: End Date, %2: End Time",
"%1 %2",
1189 dateToString( event->dtEnd(),
true, KSystemTimeZones::local() ),
1190 timeToString( event->dtEnd(),
true, KSystemTimeZones::local() ) );
1192 tmp = i18nc(
"%1: End Date",
"%1 (all day)",
1193 dateToString( event->dtEnd(),
true, KSystemTimeZones::local() ) );
1199 static QString htmlInvitationDetailsBegin()
1201 QString dir = ( QApplication::isRightToLeft() ?
"rtl" :
"ltr" );
1202 return QString(
"<div dir=\"%1\">\n" ).arg( dir );
1205 static QString htmlInvitationDetailsEnd()
1210 static QString htmlInvitationDetailsTableBegin()
1212 return "<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">";
1215 static QString htmlInvitationDetailsTableEnd()
1217 return "</table>\n";
1220 static QString diffColor()
1225 return QColor( Qt::red ).name();
1228 static QString noteColor()
1231 return qApp->palette().color( QPalette::Active, QPalette::Highlight ).name();
1234 static QString htmlRow(
const QString &title,
const QString &value )
1236 if ( !value.isEmpty() ) {
1237 return "<tr><td>" + title +
"</td><td>" + value +
"</td></tr>\n";
1243 static QString htmlRow(
const QString &title,
const QString &value,
const QString &oldvalue )
1246 if ( value.isEmpty() ) {
1251 if ( oldvalue.isEmpty() || value == oldvalue ) {
1252 return htmlRow( title, value );
1256 QString color = diffColor();
1257 QString newtitle =
"<font color=\"" + color +
"\">" + title +
"</font>";
1258 QString newvalue =
"<font color=\"" + color +
"\">" + value +
"</font>" +
1260 "(<strike>" + oldvalue +
"</strike>)";
1261 return htmlRow( newtitle, newvalue );
1274 KEMailSettings settings;
1275 QStringList profiles = settings.profiles();
1276 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
1277 settings.setProfile( *it );
1279 QString delegatorName, delegatorEmail;
1281 Attendee::List::ConstIterator it2;
1282 for ( it2 = attendees.constBegin(); it2 != attendees.constEnd(); ++it2 ) {
1284 KPIMUtils::extractEmailAddressAndName( a->delegator(), delegatorEmail, delegatorName );
1285 if ( settings.getSetting( KEMailSettings::EmailAddress ) == delegatorEmail ) {
1303 KEMailSettings settings;
1304 QStringList profiles = settings.profiles();
1305 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
1306 settings.setProfile( *it );
1309 Attendee::List::ConstIterator it2;
1310 for ( it2 = attendees.constBegin(); it2 != attendees.constEnd(); ++it2 ) {
1312 if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->email() ) {
1322 const QString &email )
1332 Attendee::List::ConstIterator it;
1333 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
1335 if ( email == a->email() ) {
1353 Attendee::List::ConstIterator it;
1354 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
1355 if ( it == attendees.constBegin() ) {
1356 rsvp = (*it)->RSVP();
1358 if ( (*it)->RSVP() != rsvp ) {
1367 static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role )
1369 if ( rsvpRequested ) {
1370 if ( role.isEmpty() ) {
1371 return i18n(
"Your response is requested" );
1373 return i18n(
"Your response as <b>%1</b> is requested", role );
1376 if ( role.isEmpty() ) {
1377 return i18n(
"No response is necessary" );
1379 return i18n(
"No response as <b>%1</b> is necessary", role );
1390 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1391 Stringify::attendeeStatus( a->status() ) );
1396 static QString invitationNote(
const QString &title,
const QString ¬e,
1397 const QString &tag,
const QString &color )
1400 if ( !note.isEmpty() ) {
1401 noteStr +=
"<table border=\"0\" style=\"margin-top:4px;\">";
1402 noteStr +=
"<tr><center><td>";
1403 if ( !color.isEmpty() ) {
1404 noteStr +=
"<font color=\"" + color +
"\">";
1406 if ( !title.isEmpty() ) {
1407 if ( !tag.isEmpty() ) {
1408 noteStr += htmlAddTag( tag, title );
1413 noteStr +=
" " + note;
1414 if ( !color.isEmpty() ) {
1415 noteStr +=
"</font>";
1417 noteStr +=
"</td></center></tr>";
1418 noteStr +=
"</table>";
1423 static QString invitationPerson(
const QString &email,
const QString &name,
const QString &uid,
1424 const QString &comment )
1426 QPair<QString, QString> s = searchNameAndUid( email, name, uid );
1427 const QString printName = s.first;
1428 const QString printUid = s.second;
1430 QString personString;
1432 if ( !printUid.isEmpty() ) {
1433 personString = htmlAddUidLink( email, printName, printUid );
1436 personString = ( printName.isEmpty() ? email : printName );
1438 if ( !comment.isEmpty() ) {
1439 personString = i18nc(
"name (comment)",
"%1 (%2)", personString, comment );
1441 personString +=
'\n';
1444 if ( !email.isEmpty() ) {
1445 personString +=
" " + htmlAddMailtoLink( email, printName );
1447 personString +=
'\n';
1449 return personString;
1452 static QString invitationDetailsIncidence(
const Incidence::Ptr &incidence,
bool noHtmlMode )
1460 QStringList comments;
1462 if ( incidence->comments().isEmpty() ) {
1463 if ( !incidence->description().isEmpty() ) {
1465 if ( !incidence->descriptionIsRich() &&
1466 !incidence->description().startsWith( QLatin1String(
"<!DOCTYPE HTML" ) ) ) {
1467 comments << string2HTML( incidence->description() );
1469 if ( !incidence->description().startsWith( QLatin1String(
"<!DOCTYPE HTML" ) ) ) {
1470 comments << incidence->richDescription();
1472 comments << incidence->description();
1475 comments[0] = cleanHtml( comments[0] );
1477 comments[0] = htmlAddTag(
"p", comments[0] );
1483 foreach (
const QString &c, incidence->comments() ) {
1484 if ( !c.isEmpty() ) {
1486 if ( !Qt::mightBeRichText( c ) ) {
1487 comments << string2HTML( c );
1490 comments << cleanHtml( cleanHtml(
"<body>" + c +
"</body>" ) );
1497 if ( !incidence->description().isEmpty() ) {
1499 if ( !incidence->descriptionIsRich() &&
1500 !incidence->description().startsWith( QLatin1String(
"<!DOCTYPE HTML" ) ) ) {
1501 descr = string2HTML( incidence->description() );
1503 if ( !incidence->description().startsWith( QLatin1String(
"<!DOCTYPE HTML" ) ) ) {
1504 descr = incidence->richDescription();
1506 descr = incidence->description();
1509 descr = cleanHtml( descr );
1511 descr = htmlAddTag(
"p", descr );
1516 if( !descr.isEmpty() ) {
1518 html +=
"<table border=\"0\" style=\"margin-top:4px;\">";
1519 html +=
"<tr><td><center>" +
1520 htmlAddTag(
"u", i18n(
"Description:" ) ) +
1521 "</center></td></tr>";
1522 html +=
"<tr><td>" + descr +
"</td></tr>";
1526 if ( !comments.isEmpty() ) {
1528 html +=
"<table border=\"0\" style=\"margin-top:4px;\">";
1529 html +=
"<tr><td><center>" +
1530 htmlAddTag(
"u", i18n(
"Comments:" ) ) +
1531 "</center></td></tr>";
1533 if ( comments.count() > 1 ) {
1535 for (
int i=0; i < comments.count(); ++i ) {
1536 html +=
"<li>" + comments[i] +
"</li>";
1540 html += comments[0];
1542 html +=
"</td></tr>";
1548 static QString invitationDetailsEvent(
const Event::Ptr &event,
bool noHtmlMode,
1549 KDateTime::Spec spec )
1556 QString html = htmlInvitationDetailsBegin();
1557 html += htmlInvitationDetailsTableBegin();
1560 html += htmlRow( i18n(
"What:" ), invitationSummary( event, noHtmlMode ) );
1561 html += htmlRow( i18n(
"Where:" ), invitationLocation( event, noHtmlMode ) );
1564 if ( event->dtStart().date() ==
event->dtEnd().date() ) {
1565 html += htmlRow( i18n(
"Date:" ),
dateToString( event->dtStart(),
false, spec ) );
1566 if ( !event->allDay() ) {
1567 html += htmlRow( i18n(
"Time:" ),
1573 html += htmlRow( i18nc(
"starting date",
"From:" ),
1575 if ( !event->allDay() ) {
1576 html += htmlRow( i18nc(
"starting time",
"At:" ),
1579 if ( event->hasEndDate() ) {
1580 html += htmlRow( i18nc(
"ending date",
"To:" ),
1582 if ( !event->allDay() ) {
1583 html += htmlRow( i18nc(
"ending time",
"At:" ),
1587 html += htmlRow( i18nc(
"ending date",
"To:" ), i18n(
"no end date specified" ) );
1595 if ( event->recurs() ) {
1599 html += htmlInvitationDetailsTableEnd();
1600 html += invitationDetailsIncidence( event, noHtmlMode );
1601 html += htmlInvitationDetailsEnd();
1608 KDateTime::Spec spec )
1611 return invitationDetailsEvent( event, noHtmlMode, spec );
1619 html += invitationNote( QString(),
1620 i18n(
"Please respond again to the original proposal." ),
1621 QString(), noteColor() );
1624 html += htmlInvitationDetailsBegin();
1625 html += htmlInvitationDetailsTableBegin();
1627 html += htmlRow( i18n(
"What:" ),
1628 invitationSummary( event, noHtmlMode ),
1629 invitationSummary( oldevent, noHtmlMode ) );
1631 html += htmlRow( i18n(
"Where:" ),
1632 invitationLocation( event, noHtmlMode ),
1633 invitationLocation( oldevent, noHtmlMode ) );
1636 if ( event->dtStart().date() ==
event->dtEnd().date() ) {
1637 html += htmlRow( i18n(
"Date:" ),
1640 QString spanStr, oldspanStr;
1641 if ( !event->allDay() ) {
1646 if ( !oldevent->allDay() ) {
1647 oldspanStr =
timeToString( oldevent->dtStart(), true ) +
1651 html += htmlRow( i18n(
"Time:" ), spanStr, oldspanStr );
1653 html += htmlRow( i18nc(
"Starting date of an event",
"From:" ),
1656 QString startStr, oldstartStr;
1657 if ( !event->allDay() ) {
1660 if ( !oldevent->allDay() ) {
1661 oldstartStr =
timeToString( oldevent->dtStart(), true );
1663 html += htmlRow( i18nc(
"Starting time of an event",
"At:" ), startStr, oldstartStr );
1664 if ( event->hasEndDate() ) {
1665 html += htmlRow( i18nc(
"Ending date of an event",
"To:" ),
1668 QString endStr, oldendStr;
1669 if ( !event->allDay() ) {
1672 if ( !oldevent->allDay() ) {
1675 html += htmlRow( i18nc(
"Starting time of an event",
"At:" ), endStr, oldendStr );
1677 QString endStr = i18n(
"no end date specified" );
1679 if ( !oldevent->hasEndDate() ) {
1680 oldendStr = i18n(
"no end date specified" );
1682 oldendStr =
dateTimeToString( oldevent->dtEnd(), oldevent->allDay(), false );
1684 html += htmlRow( i18nc(
"Ending date of an event",
"To:" ), endStr, oldendStr );
1690 QString recurStr, oldrecurStr;
1691 if ( event->recurs() || oldevent->recurs() ) {
1695 html += htmlRow( i18n(
"Recurrence:" ), recurStr, oldrecurStr );
1697 html += htmlInvitationDetailsTableEnd();
1698 html += invitationDetailsIncidence( event, noHtmlMode );
1699 html += htmlInvitationDetailsEnd();
1704 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
bool noHtmlMode,
1705 KDateTime::Spec spec )
1712 QString html = htmlInvitationDetailsBegin();
1713 html += htmlInvitationDetailsTableBegin();
1716 html += htmlRow( i18n(
"What:" ), invitationSummary( todo, noHtmlMode ) );
1717 html += htmlRow( i18n(
"Where:" ), invitationLocation( todo, noHtmlMode ) );
1719 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
1720 html += htmlRow( i18n(
"Start Date:" ),
dateToString( todo->dtStart(),
false, spec ) );
1721 if ( !todo->allDay() ) {
1722 html += htmlRow( i18n(
"Start Time:" ),
timeToString( todo->dtStart(),
false, spec ) );
1725 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
1726 html += htmlRow( i18n(
"Due Date:" ),
dateToString( todo->dtDue(),
false, spec ) );
1727 if ( !todo->allDay() ) {
1728 html += htmlRow( i18n(
"Due Time:" ),
timeToString( todo->dtDue(),
false, spec ) );
1731 html += htmlRow( i18n(
"Due Date:" ), i18nc(
"Due Date: None",
"None" ) );
1738 if ( todo->percentComplete() > 0 ) {
1739 html += htmlRow( i18n(
"Percent Done:" ), i18n(
"%1%", todo->percentComplete() ) );
1743 if ( todo->recurs() ) {
1747 html += htmlInvitationDetailsTableEnd();
1748 html += invitationDetailsIncidence( todo, noHtmlMode );
1749 html += htmlInvitationDetailsEnd();
1754 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
const Todo::Ptr &oldtodo,
1756 KDateTime::Spec spec )
1759 return invitationDetailsTodo( todo, noHtmlMode, spec );
1767 html += invitationNote( QString(),
1768 i18n(
"Please respond again to the original proposal." ),
1769 QString(), noteColor() );
1772 html += htmlInvitationDetailsBegin();
1773 html += htmlInvitationDetailsTableBegin();
1775 html += htmlRow( i18n(
"What:" ),
1776 invitationSummary( todo, noHtmlMode ),
1777 invitationSummary( todo, noHtmlMode ) );
1779 html += htmlRow( i18n(
"Where:" ),
1780 invitationLocation( todo, noHtmlMode ),
1781 invitationLocation( oldtodo, noHtmlMode ) );
1783 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
1784 html += htmlRow( i18n(
"Start Date:" ),
1787 QString startTimeStr, oldstartTimeStr;
1788 if ( !todo->allDay() || !oldtodo->allDay() ) {
1789 startTimeStr = todo->allDay() ?
1790 i18n(
"All day" ) :
timeToString( todo->dtStart(), false );
1791 oldstartTimeStr = oldtodo->allDay() ?
1792 i18n(
"All day" ) :
timeToString( oldtodo->dtStart(), false );
1794 html += htmlRow( i18n(
"Start Time:" ), startTimeStr, oldstartTimeStr );
1796 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
1797 html += htmlRow( i18n(
"Due Date:" ),
1800 QString endTimeStr, oldendTimeStr;
1801 if ( !todo->allDay() || !oldtodo->allDay() ) {
1802 endTimeStr = todo->allDay() ?
1803 i18n(
"All day" ) :
timeToString( todo->dtDue(), false );
1804 oldendTimeStr = oldtodo->allDay() ?
1805 i18n(
"All day" ) :
timeToString( oldtodo->dtDue(), false );
1807 html += htmlRow( i18n(
"Due Time:" ), endTimeStr, oldendTimeStr );
1809 QString dueStr = i18nc(
"Due Date: None",
"None" );
1811 if ( !oldtodo->hasDueDate() || !oldtodo->dtDue().isValid() ) {
1812 olddueStr = i18nc(
"Due Date: None",
"None" );
1814 olddueStr =
dateTimeToString( oldtodo->dtDue(), oldtodo->allDay(), false );
1816 html += htmlRow( i18n(
"Due Date:" ), dueStr, olddueStr );
1821 QString completionStr, oldcompletionStr;
1822 if ( todo->percentComplete() > 0 || oldtodo->percentComplete() > 0 ) {
1823 completionStr = i18n(
"%1%", todo->percentComplete() );
1824 oldcompletionStr = i18n(
"%1%", oldtodo->percentComplete() );
1826 html += htmlRow( i18n(
"Percent Done:" ), completionStr, oldcompletionStr );
1828 QString recurStr, oldrecurStr;
1829 if ( todo->recurs() || oldtodo->recurs() ) {
1833 html += htmlRow( i18n(
"Recurrence:" ), recurStr, oldrecurStr );
1835 html += htmlInvitationDetailsTableEnd();
1836 html += invitationDetailsIncidence( todo, noHtmlMode );
1838 html += htmlInvitationDetailsEnd();
1843 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
bool noHtmlMode,
1844 KDateTime::Spec spec )
1850 QString html = htmlInvitationDetailsBegin();
1851 html += htmlInvitationDetailsTableBegin();
1853 html += htmlRow( i18n(
"Summary:" ), invitationSummary( journal, noHtmlMode ) );
1854 html += htmlRow( i18n(
"Date:" ),
dateToString( journal->dtStart(),
false, spec ) );
1856 html += htmlInvitationDetailsTableEnd();
1857 html += invitationDetailsIncidence( journal, noHtmlMode );
1858 html += htmlInvitationDetailsEnd();
1863 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
1865 bool noHtmlMode, KDateTime::Spec spec )
1867 if ( !oldjournal ) {
1868 return invitationDetailsJournal( journal, noHtmlMode, spec );
1871 QString html = htmlInvitationDetailsBegin();
1872 html += htmlInvitationDetailsTableBegin();
1874 html += htmlRow( i18n(
"What:" ),
1875 invitationSummary( journal, noHtmlMode ),
1876 invitationSummary( oldjournal, noHtmlMode ) );
1878 html += htmlRow( i18n(
"Date:" ),
1882 html += htmlInvitationDetailsTableEnd();
1883 html += invitationDetailsIncidence( journal, noHtmlMode );
1884 html += htmlInvitationDetailsEnd();
1889 static QString invitationDetailsFreeBusy(
const FreeBusy::Ptr &fb,
bool noHtmlMode,
1890 KDateTime::Spec spec )
1892 Q_UNUSED( noHtmlMode );
1898 QString html = htmlInvitationDetailsTableBegin();
1900 html += htmlRow( i18n(
"Person:" ), fb->organizer()->fullName() );
1901 html += htmlRow( i18n(
"Start date:" ),
dateToString( fb->dtStart(),
true, spec ) );
1902 html += htmlRow( i18n(
"End date:" ),
dateToString( fb->dtEnd(),
true, spec ) );
1904 html +=
"<tr><td colspan=2><hr></td></tr>\n";
1905 html +=
"<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
1908 Period::List::iterator it;
1909 for ( it = periods.begin(); it != periods.end(); ++it ) {
1914 if ( dur >= 3600 ) {
1915 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600 );
1919 cont += i18ncp(
"minutes part of duration",
"1 minute",
"%1 minutes ", dur / 60 );
1923 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur );
1925 html += htmlRow( QString(),
1926 i18nc(
"startDate for duration",
"%1 for %2",
1928 per.
start().dateTime(), KLocale::LongDate ),
1932 if ( per.
start().date() == per.
end().date() ) {
1933 cont = i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1935 KGlobal::locale()->formatTime( per.
start().time() ),
1936 KGlobal::locale()->formatTime( per.
end().time() ) );
1938 cont = i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1940 per.
start().dateTime(), KLocale::LongDate ),
1941 KGlobal::locale()->formatDateTime(
1942 per.
end().dateTime(), KLocale::LongDate ) );
1945 html += htmlRow( QString(), cont );
1949 html += htmlInvitationDetailsTableEnd();
1954 bool noHtmlMode, KDateTime::Spec spec )
1957 return invitationDetailsFreeBusy( fb, noHtmlMode, spec );
1962 Q_UNUSED( incidence );
1980 static QString invitationHeaderEvent(
const Event::Ptr &event,
1984 if ( !msg || !event ) {
1988 switch ( msg->method() ) {
1990 return i18n(
"This invitation has been published" );
1992 if ( existingIncidence && event->revision() > 0 ) {
1993 QString orgStr = organizerName( event, sender );
1994 if ( senderIsOrganizer( event, sender ) ) {
1995 return i18n(
"This invitation has been updated by the organizer %1", orgStr );
1997 return i18n(
"This invitation has been updated by %1 as a representative of %2",
2001 if ( iamOrganizer( event ) ) {
2002 return i18n(
"I created this invitation" );
2004 QString orgStr = organizerName( event, sender );
2005 if ( senderIsOrganizer( event, sender ) ) {
2006 return i18n(
"You received an invitation from %1", orgStr );
2008 return i18n(
"You received an invitation from %1 as a representative of %2",
2013 return i18n(
"This invitation was refreshed" );
2015 if ( iamOrganizer( event ) ) {
2016 return i18n(
"This invitation has been canceled" );
2018 return i18n(
"The organizer has revoked the invitation" );
2021 return i18n(
"Addition to the invitation" );
2024 if ( replyMeansCounter( event ) ) {
2025 return i18n(
"%1 makes this counter proposal", firstAttendeeName( event, sender ) );
2029 if( attendees.count() == 0 ) {
2030 kDebug() <<
"No attendees in the iCal reply!";
2033 if ( attendees.count() != 1 ) {
2034 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2035 <<
"but is" << attendees.count();
2037 QString attendeeName = firstAttendeeName( event, sender );
2039 QString delegatorName, dummy;
2041 KPIMUtils::extractEmailAddressAndName( attendee->delegator(), dummy, delegatorName );
2042 if ( delegatorName.isEmpty() ) {
2043 delegatorName = attendee->delegator();
2046 switch( attendee->status() ) {
2048 return i18n(
"%1 indicates this invitation still needs some action", attendeeName );
2050 if ( event->revision() > 0 ) {
2051 if ( !sender.isEmpty() ) {
2052 return i18n(
"This invitation has been updated by attendee %1", sender );
2054 return i18n(
"This invitation has been updated by an attendee" );
2057 if ( delegatorName.isEmpty() ) {
2058 return i18n(
"%1 accepts this invitation", attendeeName );
2060 return i18n(
"%1 accepts this invitation on behalf of %2",
2061 attendeeName, delegatorName );
2065 if ( delegatorName.isEmpty() ) {
2066 return i18n(
"%1 tentatively accepts this invitation", attendeeName );
2068 return i18n(
"%1 tentatively accepts this invitation on behalf of %2",
2069 attendeeName, delegatorName );
2072 if ( delegatorName.isEmpty() ) {
2073 return i18n(
"%1 declines this invitation", attendeeName );
2075 return i18n(
"%1 declines this invitation on behalf of %2",
2076 attendeeName, delegatorName );
2080 QString delegate, dummy;
2081 KPIMUtils::extractEmailAddressAndName( attendee->delegate(), dummy, delegate );
2082 if ( delegate.isEmpty() ) {
2083 delegate = attendee->delegate();
2085 if ( !delegate.isEmpty() ) {
2086 return i18n(
"%1 has delegated this invitation to %2", attendeeName, delegate );
2088 return i18n(
"%1 has delegated this invitation", attendeeName );
2092 return i18n(
"This invitation is now completed" );
2094 return i18n(
"%1 is still processing the invitation", attendeeName );
2095 case Attendee::None:
2096 return i18n(
"Unknown response to this invitation" );
2101 return i18n(
"%1 makes this counter proposal",
2102 firstAttendeeName( event, i18n(
"Sender" ) ) );
2106 QString orgStr = organizerName( event, sender );
2107 if ( senderIsOrganizer( event, sender ) ) {
2108 return i18n(
"%1 declines your counter proposal", orgStr );
2110 return i18n(
"%1 declines your counter proposal on behalf of %2", sender, orgStr );
2115 return i18n(
"Error: Event iTIP message with unknown method" );
2117 kError() <<
"encountered an iTIP method that we do not support";
2121 static QString invitationHeaderTodo(
const Todo::Ptr &todo,
2125 if ( !msg || !todo ) {
2129 switch ( msg->method() ) {
2131 return i18n(
"This to-do has been published" );
2133 if ( existingIncidence && todo->revision() > 0 ) {
2134 QString orgStr = organizerName( todo, sender );
2135 if ( senderIsOrganizer( todo, sender ) ) {
2136 return i18n(
"This to-do has been updated by the organizer %1", orgStr );
2138 return i18n(
"This to-do has been updated by %1 as a representative of %2",
2142 if ( iamOrganizer( todo ) ) {
2143 return i18n(
"I created this to-do" );
2145 QString orgStr = organizerName( todo, sender );
2146 if ( senderIsOrganizer( todo, sender ) ) {
2147 return i18n(
"You have been assigned this to-do by %1", orgStr );
2149 return i18n(
"You have been assigned this to-do by %1 as a representative of %2",
2155 return i18n(
"This to-do was refreshed" );
2157 if ( iamOrganizer( todo ) ) {
2158 return i18n(
"This to-do was canceled" );
2160 return i18n(
"The organizer has revoked this to-do" );
2163 return i18n(
"Addition to the to-do" );
2166 if ( replyMeansCounter( todo ) ) {
2167 return i18n(
"%1 makes this counter proposal", firstAttendeeName( todo, sender ) );
2171 if ( attendees.count() == 0 ) {
2172 kDebug() <<
"No attendees in the iCal reply!";
2175 if ( attendees.count() != 1 ) {
2176 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2177 <<
"but is" << attendees.count();
2179 QString attendeeName = firstAttendeeName( todo, sender );
2181 QString delegatorName, dummy;
2183 KPIMUtils::extractEmailAddressAndName( attendee->delegate(), dummy, delegatorName );
2184 if ( delegatorName.isEmpty() ) {
2185 delegatorName = attendee->delegator();
2188 switch( attendee->status() ) {
2190 return i18n(
"%1 indicates this to-do assignment still needs some action",
2193 if ( todo->revision() > 0 ) {
2194 if ( !sender.isEmpty() ) {
2195 if ( todo->isCompleted() ) {
2196 return i18n(
"This to-do has been completed by assignee %1", sender );
2198 return i18n(
"This to-do has been updated by assignee %1", sender );
2201 if ( todo->isCompleted() ) {
2202 return i18n(
"This to-do has been completed by an assignee" );
2204 return i18n(
"This to-do has been updated by an assignee" );
2208 if ( delegatorName.isEmpty() ) {
2209 return i18n(
"%1 accepts this to-do", attendeeName );
2211 return i18n(
"%1 accepts this to-do on behalf of %2",
2212 attendeeName, delegatorName );
2216 if ( delegatorName.isEmpty() ) {
2217 return i18n(
"%1 tentatively accepts this to-do", attendeeName );
2219 return i18n(
"%1 tentatively accepts this to-do on behalf of %2",
2220 attendeeName, delegatorName );
2223 if ( delegatorName.isEmpty() ) {
2224 return i18n(
"%1 declines this to-do", attendeeName );
2226 return i18n(
"%1 declines this to-do on behalf of %2",
2227 attendeeName, delegatorName );
2231 QString delegate, dummy;
2232 KPIMUtils::extractEmailAddressAndName( attendee->delegate(), dummy, delegate );
2233 if ( delegate.isEmpty() ) {
2234 delegate = attendee->delegate();
2236 if ( !delegate.isEmpty() ) {
2237 return i18n(
"%1 has delegated this to-do to %2", attendeeName, delegate );
2239 return i18n(
"%1 has delegated this to-do", attendeeName );
2243 return i18n(
"The request for this to-do is now completed" );
2245 return i18n(
"%1 is still processing the to-do", attendeeName );
2246 case Attendee::None:
2247 return i18n(
"Unknown response to this to-do" );
2252 return i18n(
"%1 makes this counter proposal", firstAttendeeName( todo, sender ) );
2256 QString orgStr = organizerName( todo, sender );
2257 if ( senderIsOrganizer( todo, sender ) ) {
2258 return i18n(
"%1 declines the counter proposal", orgStr );
2260 return i18n(
"%1 declines the counter proposal on behalf of %2", sender, orgStr );
2265 return i18n(
"Error: To-do iTIP message with unknown method" );
2267 kError() <<
"encountered an iTIP method that we do not support";
2271 static QString invitationHeaderJournal(
const Journal::Ptr &journal,
2274 if ( !msg || !journal ) {
2278 switch ( msg->method() ) {
2280 return i18n(
"This journal has been published" );
2282 return i18n(
"You have been assigned this journal" );
2284 return i18n(
"This journal was refreshed" );
2286 return i18n(
"This journal was canceled" );
2288 return i18n(
"Addition to the journal" );
2291 if ( replyMeansCounter( journal ) ) {
2292 return i18n(
"Sender makes this counter proposal" );
2296 if ( attendees.count() == 0 ) {
2297 kDebug() <<
"No attendees in the iCal reply!";
2300 if( attendees.count() != 1 ) {
2301 kDebug() <<
"Warning: attendeecount in the reply should be 1 "
2302 <<
"but is " << attendees.count();
2306 switch( attendee->status() ) {
2308 return i18n(
"Sender indicates this journal assignment still needs some action" );
2310 return i18n(
"Sender accepts this journal" );
2312 return i18n(
"Sender tentatively accepts this journal" );
2314 return i18n(
"Sender declines this journal" );
2316 return i18n(
"Sender has delegated this request for the journal" );
2318 return i18n(
"The request for this journal is now completed" );
2320 return i18n(
"Sender is still processing the invitation" );
2321 case Attendee::None:
2322 return i18n(
"Unknown response to this journal" );
2327 return i18n(
"Sender makes this counter proposal" );
2329 return i18n(
"Sender declines the counter proposal" );
2331 return i18n(
"Error: Journal iTIP message with unknown method" );
2333 kError() <<
"encountered an iTIP method that we do not support";
2337 static QString invitationHeaderFreeBusy(
const FreeBusy::Ptr &fb,
2340 if ( !msg || !fb ) {
2344 switch ( msg->method() ) {
2346 return i18n(
"This free/busy list has been published" );
2348 return i18n(
"The free/busy list has been requested" );
2350 return i18n(
"This free/busy list was refreshed" );
2352 return i18n(
"This free/busy list was canceled" );
2354 return i18n(
"Addition to the free/busy list" );
2356 return i18n(
"Reply to the free/busy list" );
2358 return i18n(
"Sender makes this counter proposal" );
2360 return i18n(
"Sender declines the counter proposal" );
2362 return i18n(
"Error: Free/Busy iTIP message with unknown method" );
2364 kError() <<
"encountered an iTIP method that we do not support";
2369 static QString invitationAttendeeList(
const Incidence::Ptr &incidence )
2376 tmpStr += i18n(
"Assignees" );
2378 tmpStr += i18n(
"Invitation List" );
2383 if ( !attendees.isEmpty() ) {
2384 QStringList comments;
2385 Attendee::List::ConstIterator it;
2386 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
2388 if ( !iamAttendee( a ) ) {
2391 tmpStr +=
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">";
2396 if ( attendeeIsOrganizer( incidence, a ) ) {
2397 comments << i18n(
"organizer" );
2399 if ( !a->delegator().isEmpty() ) {
2400 comments << i18n(
" (delegated by %1)", a->delegator() );
2402 if ( !a->delegate().isEmpty() ) {
2403 comments << i18n(
" (delegated to %1)", a->delegate() );
2405 tmpStr += invitationPerson( a->email(), a->name(), QString(), comments.join(
"," ) );
2412 tmpStr +=
"</table>";
2427 tmpStr += i18n(
"Assignees" );
2429 tmpStr += i18n(
"Invitation List" );
2434 if ( !attendees.isEmpty() ) {
2435 QStringList comments;
2436 Attendee::List::ConstIterator it;
2437 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
2439 if ( !attendeeIsOrganizer( incidence, a ) ) {
2440 QString statusStr = Stringify::attendeeStatus( a->status () );
2441 if ( sender && ( a->email() == sender->email() ) ) {
2444 if ( a->status() != sender->status() ) {
2445 statusStr = i18n(
"%1 (<i>unrecorded</i>)",
2446 Stringify::attendeeStatus( sender->status() ) );
2452 tmpStr +=
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">";
2457 if ( iamAttendee( a ) ) {
2458 comments << i18n(
"myself" );
2460 if ( !a->delegator().isEmpty() ) {
2461 comments << i18n(
" (delegated by %1)", a->delegator() );
2463 if ( !a->delegate().isEmpty() ) {
2464 comments << i18n(
" (delegated to %1)", a->delegate() );
2466 tmpStr += invitationPerson( a->email(), a->name(), QString(), comments.join(
"," ) );
2468 tmpStr +=
"<td>" + statusStr +
"</td>";
2474 tmpStr +=
"</table>";
2476 tmpStr +=
"<i> " + i18nc(
"no attendees",
"None" ) +
"</i>";
2482 static QString invitationAttachments( InvitationFormatterHelper *helper,
2491 if ( !attachments.isEmpty() ) {
2492 tmpStr += i18n(
"Attached Documents:" ) +
"<ol>";
2494 Attachment::List::ConstIterator it;
2495 for ( it = attachments.constBegin(); it != attachments.constEnd(); ++it ) {
2499 KMimeType::Ptr
mimeType = KMimeType::mimeType( a->mimeType() );
2500 const QString iconStr = ( mimeType ?
2501 mimeType->iconName( a->uri() ) :
2502 QString(
"application-octet-stream" ) );
2503 const QString iconPath = KIconLoader::global()->iconPath( iconStr, KIconLoader::Small );
2504 if ( !iconPath.isEmpty() ) {
2505 tmpStr +=
"<img valign=\"top\" src=\"" + iconPath +
"\">";
2507 tmpStr += helper->makeLink(
"ATTACH:" + a->label().toUtf8().toBase64(), a->label() );
2517 class KCalUtils::IncidenceFormatter::ScheduleMessageVisitor :
public Visitor
2520 ScheduleMessageVisitor() : mMessage( 0 ) { mResult =
""; }
2525 mExistingIncidence = existingIncidence;
2528 return incidence->accept( *
this, incidence );
2530 QString result()
const {
return mResult; }
2539 class KCalUtils::IncidenceFormatter::InvitationHeaderVisitor :
2540 public IncidenceFormatter::ScheduleMessageVisitor
2545 mResult = invitationHeaderEvent( event, mExistingIncidence, mMessage, mSender );
2546 return !mResult.isEmpty();
2550 mResult = invitationHeaderTodo( todo, mExistingIncidence, mMessage, mSender );
2551 return !mResult.isEmpty();
2555 mResult = invitationHeaderJournal( journal, mMessage );
2556 return !mResult.isEmpty();
2560 mResult = invitationHeaderFreeBusy( fb, mMessage );
2561 return !mResult.isEmpty();
2565 class KCalUtils::IncidenceFormatter::InvitationBodyVisitor
2566 :
public IncidenceFormatter::ScheduleMessageVisitor
2569 InvitationBodyVisitor(
bool noHtmlMode, KDateTime::Spec spec )
2570 : ScheduleMessageVisitor(), mNoHtmlMode( noHtmlMode ), mSpec( spec ) {}
2576 mResult = invitationDetailsEvent( event, oldevent, mMessage, mNoHtmlMode, mSpec );
2577 return !mResult.isEmpty();
2582 mResult = invitationDetailsTodo( todo, oldtodo, mMessage, mNoHtmlMode, mSpec );
2583 return !mResult.isEmpty();
2588 mResult = invitationDetailsJournal( journal, oldjournal, mNoHtmlMode, mSpec );
2589 return !mResult.isEmpty();
2593 mResult = invitationDetailsFreeBusy( fb,
FreeBusy::Ptr(), mNoHtmlMode, mSpec );
2594 return !mResult.isEmpty();
2599 KDateTime::Spec mSpec;
2603 InvitationFormatterHelper::InvitationFormatterHelper()
2608 InvitationFormatterHelper::~InvitationFormatterHelper()
2612 QString InvitationFormatterHelper::generateLinkURL(
const QString &
id )
2618 class IncidenceFormatter::IncidenceCompareVisitor :
public Visitor
2621 IncidenceCompareVisitor() {}
2625 if ( !existingIncidence ) {
2629 if ( !inc || !existingIncidence ||
2630 inc->revision() <= existingIncidence->revision() ) {
2633 mExistingIncidence = existingIncidence;
2634 return incidence->
accept( *
this, incidence );
2637 QString result()
const
2639 if ( mChanges.isEmpty() ) {
2642 QString html =
"<div align=\"left\"><ul><li>";
2643 html += mChanges.join(
"</li><li>" );
2644 html +=
"</li><ul></div>";
2651 compareEvents( event, mExistingIncidence.dynamicCast<
Event>() );
2652 compareIncidences( event, mExistingIncidence );
2653 return !mChanges.isEmpty();
2657 compareTodos( todo, mExistingIncidence.dynamicCast<
Todo>() );
2658 compareIncidences( todo, mExistingIncidence );
2659 return !mChanges.isEmpty();
2663 compareIncidences( journal, mExistingIncidence );
2664 return !mChanges.isEmpty();
2669 return !mChanges.isEmpty();
2673 void compareEvents(
const Event::Ptr &newEvent,
2676 if ( !oldEvent || !newEvent ) {
2679 if ( oldEvent->dtStart() != newEvent->dtStart() ||
2680 oldEvent->allDay() != newEvent->allDay() ) {
2681 mChanges += i18n(
"The invitation starting time has been changed from %1 to %2",
2682 eventStartTimeStr( oldEvent ), eventStartTimeStr( newEvent ) );
2684 if ( oldEvent->dtEnd() != newEvent->dtEnd() ||
2685 oldEvent->allDay() != newEvent->allDay() ) {
2686 mChanges += i18n(
"The invitation ending time has been changed from %1 to %2",
2687 eventEndTimeStr( oldEvent ), eventEndTimeStr( newEvent ) );
2691 void compareTodos(
const Todo::Ptr &newTodo,
2694 if ( !oldTodo || !newTodo ) {
2698 if ( !oldTodo->isCompleted() && newTodo->isCompleted() ) {
2699 mChanges += i18n(
"The to-do has been completed" );
2701 if ( oldTodo->isCompleted() && !newTodo->isCompleted() ) {
2702 mChanges += i18n(
"The to-do is no longer completed" );
2704 if ( oldTodo->percentComplete() != newTodo->percentComplete() ) {
2705 const QString oldPer = i18n(
"%1%", oldTodo->percentComplete() );
2706 const QString newPer = i18n(
"%1%", newTodo->percentComplete() );
2707 mChanges += i18n(
"The task completed percentage has changed from %1 to %2",
2711 if ( !oldTodo->hasStartDate() && newTodo->hasStartDate() ) {
2712 mChanges += i18n(
"A to-do starting time has been added" );
2714 if ( oldTodo->hasStartDate() && !newTodo->hasStartDate() ) {
2715 mChanges += i18n(
"The to-do starting time has been removed" );
2717 if ( oldTodo->hasStartDate() && newTodo->hasStartDate() &&
2718 oldTodo->dtStart() != newTodo->dtStart() ) {
2719 mChanges += i18n(
"The to-do starting time has been changed from %1 to %2",
2724 if ( !oldTodo->hasDueDate() && newTodo->hasDueDate() ) {
2725 mChanges += i18n(
"A to-do due time has been added" );
2727 if ( oldTodo->hasDueDate() && !newTodo->hasDueDate() ) {
2728 mChanges += i18n(
"The to-do due time has been removed" );
2730 if ( oldTodo->hasDueDate() && newTodo->hasDueDate() &&
2731 oldTodo->dtDue() != newTodo->dtDue() ) {
2732 mChanges += i18n(
"The to-do due time has been changed from %1 to %2",
2741 if ( !oldInc || !newInc ) {
2745 if ( oldInc->summary() != newInc->summary() ) {
2746 mChanges += i18n(
"The summary has been changed to: \"%1\"",
2747 newInc->richSummary() );
2750 if ( oldInc->location() != newInc->location() ) {
2751 mChanges += i18n(
"The location has been changed to: \"%1\"",
2752 newInc->richLocation() );
2755 if ( oldInc->description() != newInc->description() ) {
2756 mChanges += i18n(
"The description has been changed to: \"%1\"",
2757 newInc->richDescription() );
2762 for ( Attendee::List::ConstIterator it = newAttendees.constBegin();
2763 it != newAttendees.constEnd(); ++it ) {
2764 Attendee::Ptr oldAtt = oldInc->attendeeByMail( (*it)->email() );
2766 mChanges += i18n(
"Attendee %1 has been added", (*it)->fullName() );
2768 if ( oldAtt->status() != (*it)->status() ) {
2769 mChanges += i18n(
"The status of attendee %1 has been changed to: %2",
2770 (*it)->fullName(), Stringify::attendeeStatus( (*it)->status() ) );
2775 for ( Attendee::List::ConstIterator it = oldAttendees.constBegin();
2776 it != oldAttendees.constEnd(); ++it ) {
2777 if ( !attendeeIsOrganizer( oldInc, (*it) ) ) {
2778 Attendee::Ptr newAtt = newInc->attendeeByMail( (*it)->email() );
2780 mChanges += i18n(
"Attendee %1 has been removed", (*it)->fullName() );
2788 QStringList mChanges;
2792 QString InvitationFormatterHelper::makeLink(
const QString &
id,
const QString &text )
2794 if ( !
id.startsWith( QLatin1String(
"ATTACH:" ) ) ) {
2795 QString res = QString(
"<a href=\"%1\"><b>%2</b></a>" ).
2796 arg( generateLinkURL(
id ), text );
2800 QString res = QString(
"<a href=\"%1\">%2</a>" ).
2801 arg( generateLinkURL(
id ), text );
2808 static bool incidenceOwnedByMe(
const Calendar::Ptr &calendar,
2811 Q_UNUSED( calendar );
2812 Q_UNUSED( incidence );
2817 static QString tdOpen =
"<td style=\"border-width:2px;border-style:outset\">";
2818 static QString tdClose =
"</td>";
2821 bool rsvpReq,
bool rsvpRec,
2822 InvitationFormatterHelper *helper )
2829 if ( !rsvpReq && ( inc && inc->revision() == 0 ) ) {
2832 html += helper->makeLink(
"record", i18n(
"[Record]" ) );
2837 html += helper->makeLink(
"delete", i18n(
"[Move to Trash]" ) );
2844 html += helper->makeLink(
"accept", i18nc(
"accept invitation",
"Accept" ) );
2849 html += helper->makeLink(
"accept_conditionally",
2850 i18nc(
"Accept invitation conditionally",
"Accept cond." ) );
2855 html += helper->makeLink(
"counter",
2856 i18nc(
"invitation counter proposal",
"Counter proposal" ) );
2861 html += helper->makeLink(
"decline",
2862 i18nc(
"decline invitation",
"Decline" ) );
2866 if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
2869 html += helper->makeLink(
"delegate",
2870 i18nc(
"delegate inviation to another",
"Delegate" ) );
2875 html += helper->makeLink(
"forward",
2876 i18nc(
"forward request to another",
"Forward" ) );
2880 if ( inc && inc->type() == Incidence::TypeEvent ) {
2882 html += helper->makeLink(
"check_calendar",
2883 i18nc(
"look for scheduling conflicts",
"Check my calendar" ) );
2891 InvitationFormatterHelper *helper )
2900 html += helper->makeLink(
"accept_counter", i18n(
"[Accept]" ) );
2905 html += helper->makeLink(
"decline_counter", i18n(
"[Decline]" ) );
2909 if ( incidence && incidence->type() == Incidence::TypeEvent ) {
2911 html += helper->makeLink(
"check_calendar", i18n(
"[Check my calendar] " ) );
2922 static QString formatICalInvitationHelper( QString invitation,
2924 InvitationFormatterHelper *helper,
2926 KDateTime::Spec spec,
2927 const QString &sender,
2928 bool outlookCompareStyle )
2930 if ( invitation.isEmpty() ) {
2940 kDebug() <<
"Failed to parse the scheduling message";
2948 incBase->shiftTimes( mCalendar->timeSpec(), KDateTime::Spec::LocalZone() );
2952 if ( incBase && helper->calendar() ) {
2953 existingIncidence = helper->calendar()->incidence( incBase->uid() );
2955 if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) ) {
2956 existingIncidence.clear();
2958 if ( !existingIncidence ) {
2960 for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
2961 if ( (*it)->schedulingID() == incBase->uid() &&
2962 incidenceOwnedByMe( helper->calendar(), *it ) ) {
2963 existingIncidence = *it;
2974 html +=
"<div align=\"center\" style=\"border:solid 1px;\">";
2976 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
2978 if ( !headerVisitor.act( inc, existingIncidence, msg, sender ) ) {
2981 html += htmlAddTag(
"h3", headerVisitor.result() );
2983 if ( outlookCompareStyle ||
2986 IncidenceFormatter::InvitationBodyVisitor bodyVisitor( noHtmlMode, spec );
2990 if ( inc && existingIncidence &&
2991 inc->revision() < existingIncidence->revision() ) {
2992 bodyOk = bodyVisitor.act( existingIncidence, inc, msg, sender );
2994 bodyOk = bodyVisitor.act( inc, existingIncidence, msg, sender );
3000 html += bodyVisitor.result();
3006 InvitationBodyVisitor bodyVisitor( noHtmlMode, spec );
3010 html += bodyVisitor.result();
3013 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
3014 if ( compareVisitor.act( inc, existingIncidence ) ) {
3015 html +=
"<p align=\"left\">";
3016 if ( senderIsOrganizer( inc, sender ) ) {
3017 html += i18n(
"The following changes have been made by the organizer:" );
3018 }
else if ( !sender.isEmpty() ) {
3019 html += i18n(
"The following changes have been made by %1:", sender );
3021 html += i18n(
"The following changes have been made:" );
3024 html += compareVisitor.result();
3028 IncidenceCompareVisitor compareVisitor;
3029 if ( compareVisitor.act( inc, existingIncidence ) ) {
3030 html +=
"<p align=\"left\">";
3031 if ( !sender.isEmpty() ) {
3032 html += i18n(
"The following changes have been made by %1:", sender );
3034 html += i18n(
"The following changes have been made by an attendee:" );
3037 html += compareVisitor.result();
3043 bool myInc = iamOrganizer( inc );
3046 bool rsvpRec =
false;
3050 if ( !rsvpIncidence && inc && inc->revision() > 0 ) {
3051 rsvpIncidence = inc;
3053 if ( rsvpIncidence ) {
3054 ea = findMyAttendee( rsvpIncidence );
3057 ( ea->status() == Attendee::Accepted ||
3058 ea->status() == Attendee::Declined ||
3059 ea->status() == Attendee::Tentative ) ) {
3066 bool isDelegated =
false;
3069 if ( !inc->attendees().isEmpty() ) {
3070 a = inc->attendees().first();
3074 isDelegated = ( a->status() == Attendee::Delegated );
3075 role = Stringify::attendeeRole( a->role() );
3079 bool rsvpReq = rsvpRequested( inc );
3080 if ( !myInc && a ) {
3083 if ( rsvpRec && inc ) {
3084 if ( inc->revision() == 0 ) {
3085 html += i18n(
"Your <b>%1</b> response has been recorded",
3086 Stringify::attendeeStatus( ea->status() ) );
3088 html += i18n(
"Your status for this invitation is <b>%1</b>",
3089 Stringify::attendeeStatus( ea->status() ) );
3093 html += i18n(
"This invitation was canceled" );
3094 }
else if ( msg->method() ==
iTIPAdd ) {
3095 html += i18n(
"This invitation was accepted" );
3098 html += rsvpRequestedStr( rsvpReq, role );
3100 if ( !isDelegated ) {
3101 html += rsvpRequestedStr( rsvpReq, role );
3103 html += i18n(
"Awaiting delegation response" );
3111 if ( inc && inc->revision() == 0 ) {
3112 QString statStr = myStatusStr( inc );
3113 if ( !statStr.isEmpty() ) {
3125 html +=
"<table border=\"0\" align=\"center\" cellspacing=\"4\"><tr>";
3127 switch ( msg->method() ) {
3133 if ( inc && inc->revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
3134 if ( inc->type() == Incidence::TypeTodo ) {
3135 html += helper->makeLink(
"reply", i18n(
"[Record invitation in my to-do list]" ) );
3137 html += helper->makeLink(
"reply", i18n(
"[Record invitation in my calendar]" ) );
3141 if ( !myInc && a ) {
3142 html += responseButtons( inc, rsvpReq, rsvpRec, helper );
3151 if ( inc->type() == Incidence::TypeTodo ) {
3152 html += helper->makeLink(
"cancel",
3153 i18n(
"Remove invitation from my to-do list" ) );
3155 html += helper->makeLink(
"cancel",
3156 i18n(
"Remove invitation from my calendar" ) );
3169 if ( replyMeansCounter( inc ) ) {
3170 html +=
"<tr>" + counterButtons( inc, helper ) +
"</tr>";
3179 a = findDelegatedFromMyAttendee( inc );
3181 if ( a->status() != Attendee::Accepted ||
3182 a->status() != Attendee::Tentative ) {
3183 html += responseButtons( inc, rsvpReq, rsvpRec, helper );
3189 if ( !inc->attendees().isEmpty() ) {
3190 a = inc->attendees().first();
3192 if ( a && helper->calendar() ) {
3193 ea = findAttendee( existingIncidence, a->email() );
3196 if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
3198 html += htmlAddTag(
"i", i18n(
"The <b>%1</b> response has been recorded",
3199 Stringify::attendeeStatus( ea->status() ) ) );
3203 if ( inc->type() == Incidence::TypeTodo ) {
3204 html += helper->makeLink(
"reply", i18n(
"[Record response in my to-do list]" ) );
3206 html += helper->makeLink(
"reply", i18n(
"[Record response in my calendar]" ) );
3215 html += counterButtons( inc, helper );
3219 html += responseButtons( inc, rsvpReq, rsvpRec, helper );
3227 html +=
"</tr></table>";
3231 html += invitationRsvpList( existingIncidence, a );
3233 html += invitationAttendeeList( inc );
3240 html += invitationAttachments( helper, inc );
3248 InvitationFormatterHelper *helper,
3249 bool outlookCompareStyle )
3251 return formatICalInvitationHelper( invitation, calendar, helper,
false,
3252 KSystemTimeZones::local(), QString(),
3253 outlookCompareStyle );
3258 InvitationFormatterHelper *helper,
3259 const QString &sender,
3260 bool outlookCompareStyle )
3262 return formatICalInvitationHelper( invitation, calendar, helper,
true,
3263 KSystemTimeZones::local(), sender,
3264 outlookCompareStyle );
3272 class KCalUtils::IncidenceFormatter::ToolTipVisitor :
public Visitor
3276 : mRichText( true ), mSpec( KDateTime::Spec() ), mResult(
"" ) {}
3280 const QDate &date=QDate(),
bool richText=
true,
3281 KDateTime::Spec spec=KDateTime::Spec() )
3283 mCalendar = calendar;
3286 mRichText = richText;
3289 return incidence ? incidence->
accept( *
this, incidence ) :
false;
3293 const QDate &date=QDate(),
bool richText=
true,
3294 KDateTime::Spec spec=KDateTime::Spec() )
3296 mLocation = location;
3298 mRichText = richText;
3301 return incidence ? incidence->
accept( *
this, incidence ) :
false;
3304 QString result()
const {
return mResult; }
3312 QString dateRangeText(
const Event::Ptr &event,
const QDate &date );
3313 QString dateRangeText(
const Todo::Ptr &todo,
const QDate &date );
3317 QString generateToolTip(
const Incidence::Ptr &incidence, QString dtRangeText );
3324 KDateTime::Spec mSpec;
3328 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Event::Ptr &event,
3335 KDateTime startDt =
event->
dtStart();
3336 KDateTime endDt =
event->dtEnd();
3337 if ( event->recurs() ) {
3338 if ( date.isValid() ) {
3339 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
3340 int diffDays = startDt.daysTo( kdt );
3341 kdt = kdt.addSecs( -1 );
3342 startDt.setDate( event->recurrence()->getNextDateTime( kdt ).date() );
3343 if ( event->hasEndDate() ) {
3344 endDt = endDt.addDays( diffDays );
3345 if ( startDt > endDt ) {
3346 startDt.setDate( event->recurrence()->getPreviousDateTime( kdt ).date() );
3347 endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
3353 if ( event->isMultiDay() ) {
3355 ret +=
"<br>" + i18nc(
"Event start",
"<i>From:</i> %1", tmp );
3358 ret +=
"<br>" + i18nc(
"Event end",
"<i>To:</i> %1", tmp );
3363 i18n(
"<i>Date:</i> %1",
dateToString( startDt,
false, mSpec ) );
3364 if ( !event->allDay() ) {
3365 const QString dtStartTime =
timeToString( startDt,
true, mSpec );
3366 const QString dtEndTime =
timeToString( endDt,
true, mSpec );
3367 if ( dtStartTime == dtEndTime ) {
3370 i18nc(
"time for event",
"<i>Time:</i> %1",
3374 i18nc(
"time range for event",
3375 "<i>Time:</i> %1 - %2",
3376 dtStartTime, dtEndTime );
3381 return ret.replace(
' ',
" " );
3384 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Todo::Ptr &todo,
3389 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
3390 KDateTime startDt = todo->dtStart();
3391 if ( todo->recurs() ) {
3392 if ( date.isValid() ) {
3393 startDt.setDate( date );
3397 i18n(
"<i>Start:</i> %1",
dateToString( startDt,
false, mSpec ) );
3400 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
3401 KDateTime dueDt = todo->dtDue();
3402 if ( todo->recurs() ) {
3403 if ( date.isValid() ) {
3404 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
3405 kdt = kdt.addSecs( -1 );
3406 dueDt.setDate( todo->recurrence()->getNextDateTime( kdt ).date() );
3410 i18n(
"<i>Due:</i> %1",
3416 if ( todo->priority() > 0 ) {
3418 ret +=
"<i>" + i18n(
"Priority:" ) +
"</i>" +
" ";
3419 ret += QString::number( todo->priority() );
3423 if ( todo->isCompleted() ) {
3424 ret +=
"<i>" + i18nc(
"Completed: date",
"Completed:" ) +
"</i>" +
" ";
3427 ret +=
"<i>" + i18n(
"Percent Done:" ) +
"</i>" +
" ";
3428 ret += i18n(
"%1%", todo->percentComplete() );
3431 return ret.replace(
' ',
" " );
3434 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Journal::Ptr &journal )
3438 if ( journal->dtStart().isValid() ) {
3440 i18n(
"<i>Date:</i> %1",
dateToString( journal->dtStart(),
false, mSpec ) );
3442 return ret.replace(
' ',
" " );
3445 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const FreeBusy::Ptr &fb )
3450 i18n(
"<i>Period start:</i> %1",
3453 i18n(
"<i>Period start:</i> %1",
3455 return ret.replace(
' ',
" " );
3460 mResult = generateToolTip( event, dateRangeText( event, mDate ) );
3461 return !mResult.isEmpty();
3466 mResult = generateToolTip( todo, dateRangeText( todo, mDate ) );
3467 return !mResult.isEmpty();
3472 mResult = generateToolTip( journal, dateRangeText( journal ) );
3473 return !mResult.isEmpty();
3479 mResult =
"<qt><b>" +
3480 i18n(
"Free/Busy information for %1", fb->organizer()->fullName() ) +
3482 mResult += dateRangeText( fb );
3484 return !mResult.isEmpty();
3487 static QString tooltipPerson(
const QString &email,
const QString &name,
Attendee::PartStat status )
3490 const QString printName = searchName( email, name );
3493 const QString iconPath = rsvpStatusIconPath( status );
3496 QString personString;
3497 if ( !iconPath.isEmpty() ) {
3498 personString +=
"<img valign=\"top\" src=\"" + iconPath +
"\">" +
" ";
3500 if ( status != Attendee::None ) {
3501 personString += i18nc(
"attendee name (attendee status)",
"%1 (%2)",
3502 printName.isEmpty() ? email : printName,
3503 Stringify::attendeeStatus( status ) );
3505 personString += i18n(
"%1", printName.isEmpty() ? email : printName );
3507 return personString;
3510 static QString tooltipFormatOrganizer(
const QString &email,
const QString &name )
3513 const QString printName = searchName( email, name );
3516 const QString iconPath =
3517 KIconLoader::global()->iconPath(
"meeting-organizer", KIconLoader::Small );
3520 QString personString;
3521 personString +=
"<img valign=\"top\" src=\"" + iconPath +
"\">" +
" ";
3522 personString += ( printName.isEmpty() ? email : printName );
3523 return personString;
3526 static QString tooltipFormatAttendeeRoleList(
const Incidence::Ptr &incidence,
3530 const QString etc = i18nc(
"elipsis",
"..." );
3534 Attendee::List::ConstIterator it;
3537 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
3539 if ( a->role() != role ) {
3543 if ( attendeeIsOrganizer( incidence, a ) ) {
3547 if ( i == maxNumAtts ) {
3548 tmpStr +=
" " + etc;
3551 tmpStr +=
" " + tooltipPerson( a->email(), a->name(),
3552 showStatus ? a->status() : Attendee::None );
3553 if ( !a->delegator().isEmpty() ) {
3554 tmpStr += i18n(
" (delegated by %1)", a->delegator() );
3556 if ( !a->delegate().isEmpty() ) {
3557 tmpStr += i18n(
" (delegated to %1)", a->delegate() );
3562 if ( tmpStr.endsWith( QLatin1String(
"<br>" ) ) ) {
3568 static QString tooltipFormatAttendees(
const Calendar::Ptr &calendar,
3571 QString tmpStr, str;
3574 int attendeeCount = incidence->attendees().count();
3575 if ( attendeeCount > 1 ||
3576 ( attendeeCount == 1 &&
3577 !attendeeIsOrganizer( incidence, incidence->attendees().first() ) ) ) {
3578 tmpStr +=
"<i>" + i18n(
"Organizer:" ) +
"</i>" +
"<br>";
3579 tmpStr +=
" " + tooltipFormatOrganizer( incidence->organizer()->email(),
3580 incidence->organizer()->name() );
3585 const bool showStatus = attendeeCount > 0 && incOrganizerOwnsCalendar( calendar, incidence );
3588 str = tooltipFormatAttendeeRoleList( incidence, Attendee::Chair, showStatus );
3589 if ( !str.isEmpty() ) {
3590 tmpStr +=
"<br><i>" + i18n(
"Chair:" ) +
"</i>" +
"<br>";
3595 str = tooltipFormatAttendeeRoleList( incidence, Attendee::ReqParticipant, showStatus );
3596 if ( !str.isEmpty() ) {
3597 tmpStr +=
"<br><i>" + i18n(
"Required Participants:" ) +
"</i>" +
"<br>";
3602 str = tooltipFormatAttendeeRoleList( incidence, Attendee::OptParticipant, showStatus );
3603 if ( !str.isEmpty() ) {
3604 tmpStr +=
"<br><i>" + i18n(
"Optional Participants:" ) +
"</i>" +
"<br>";
3609 str = tooltipFormatAttendeeRoleList( incidence, Attendee::NonParticipant, showStatus );
3610 if ( !str.isEmpty() ) {
3611 tmpStr +=
"<br><i>" + i18n(
"Observers:" ) +
"</i>" +
"<br>";
3618 QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
const Incidence::Ptr &incidence,
3619 QString dtRangeText )
3621 int maxDescLen = 120;
3628 QString tmp =
"<qt>";
3631 tmp +=
"<b>" + incidence->richSummary() +
"</b>";
3634 QString calStr = mLocation;
3638 if ( !calStr.isEmpty() ) {
3639 tmp +=
"<i>" + i18n(
"Calendar:" ) +
"</i>" +
" ";
3645 if ( !incidence->location().isEmpty() ) {
3647 tmp +=
"<i>" + i18n(
"Location:" ) +
"</i>" +
" ";
3648 tmp += incidence->richLocation();
3652 if ( !durStr.isEmpty() ) {
3654 tmp +=
"<i>" + i18n(
"Duration:" ) +
"</i>" +
" ";
3658 if ( incidence->recurs() ) {
3660 tmp +=
"<i>" + i18n(
"Recurrence:" ) +
"</i>" +
" ";
3664 if ( !incidence->description().isEmpty() ) {
3665 QString desc( incidence->description() );
3666 if ( !incidence->descriptionIsRich() ) {
3667 if ( desc.length() > maxDescLen ) {
3668 desc = desc.left( maxDescLen ) + i18nc(
"elipsis",
"..." );
3670 desc = Qt::escape( desc ).replace(
'\n',
"<br>" );
3675 tmp +=
"<i>" + i18n(
"Description:" ) +
"</i>" +
"<br>";
3680 int reminderCount = incidence->alarms().count();
3681 if ( reminderCount > 0 && incidence->hasEnabledAlarms() ) {
3683 tmp +=
"<i>" + i18np(
"Reminder:",
"Reminders:", reminderCount ) +
"</i>" +
" ";
3688 tmp += tooltipFormatAttendees( mCalendar, incidence );
3690 int categoryCount = incidence->categories().count();
3691 if ( categoryCount > 0 ) {
3693 tmp +=
"<i>" + i18np(
"Category:",
"Categories:", categoryCount ) +
"</i>" +
" ";
3694 tmp += incidence->categories().join(
", " );
3706 KDateTime::Spec spec )
3709 if ( v.act( sourceName, incidence, date, richText, spec ) ) {
3721 static QString mailBodyIncidence(
const Incidence::Ptr &incidence )
3724 if ( !incidence->summary().isEmpty() ) {
3725 body += i18n(
"Summary: %1\n", incidence->richSummary() );
3727 if ( !incidence->organizer()->isEmpty() ) {
3728 body += i18n(
"Organizer: %1\n", incidence->organizer()->fullName() );
3730 if ( !incidence->location().isEmpty() ) {
3731 body += i18n(
"Location: %1\n", incidence->richLocation() );
3738 class KCalUtils::IncidenceFormatter::MailBodyVisitor :
public Visitor
3742 : mSpec( KDateTime::Spec() ), mResult(
"" ) {}
3748 return incidence ? incidence->accept( *
this, incidence ) :
false;
3750 QString result()
const
3761 mResult = i18n(
"This is a Free Busy Object" );
3762 return !mResult.isEmpty();
3765 KDateTime::Spec mSpec;
3771 QString recurrence[]= {
3772 i18nc(
"no recurrence",
"None" ),
3773 i18nc(
"event recurs by minutes",
"Minutely" ),
3774 i18nc(
"event recurs by hours",
"Hourly" ),
3775 i18nc(
"event recurs by days",
"Daily" ),
3776 i18nc(
"event recurs by weeks",
"Weekly" ),
3777 i18nc(
"event recurs same position (e.g. first monday) each month",
"Monthly Same Position" ),
3778 i18nc(
"event recurs same day each month",
"Monthly Same Day" ),
3779 i18nc(
"event recurs same month each year",
"Yearly Same Month" ),
3780 i18nc(
"event recurs same day each year",
"Yearly Same Day" ),
3781 i18nc(
"event recurs same position (e.g. first monday) each year",
"Yearly Same Position" )
3784 mResult = mailBodyIncidence( event );
3785 mResult += i18n(
"Start Date: %1\n",
dateToString( event->dtStart(),
true, mSpec ) );
3786 if ( !event->allDay() ) {
3787 mResult += i18n(
"Start Time: %1\n",
timeToString( event->dtStart(),
true, mSpec ) );
3789 if ( event->dtStart() !=
event->dtEnd() ) {
3790 mResult += i18n(
"End Date: %1\n",
dateToString( event->dtEnd(),
true, mSpec ) );
3792 if ( !event->allDay() ) {
3793 mResult += i18n(
"End Time: %1\n",
timeToString( event->dtEnd(),
true, mSpec ) );
3795 if ( event->recurs() ) {
3798 mResult += i18n(
"Recurs: %1\n", recurrence[ recur->
recurrenceType() ] );
3799 mResult += i18n(
"Frequency: %1\n", event->recurrence()->frequency() );
3802 mResult += i18np(
"Repeats once",
"Repeats %1 times", recur->
duration() );
3808 if ( event->allDay() ) {
3809 endstr = KGlobal::locale()->formatDate( recur->
endDate() );
3811 endstr = KGlobal::locale()->formatDateTime( recur->
endDateTime().dateTime() );
3813 mResult += i18n(
"Repeat until: %1\n", endstr );
3815 mResult += i18n(
"Repeats forever\n" );
3820 QString details =
event->richDescription();
3821 if ( !details.isEmpty() ) {
3822 mResult += i18n(
"Details:\n%1\n", details );
3824 return !mResult.isEmpty();
3829 mResult = mailBodyIncidence( todo );
3831 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
3832 mResult += i18n(
"Start Date: %1\n",
dateToString( todo->dtStart(
false ),
true, mSpec ) );
3833 if ( !todo->allDay() ) {
3834 mResult += i18n(
"Start Time: %1\n",
timeToString( todo->dtStart(
false ),
true, mSpec ) );
3837 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
3838 mResult += i18n(
"Due Date: %1\n",
dateToString( todo->dtDue(),
true, mSpec ) );
3839 if ( !todo->allDay() ) {
3840 mResult += i18n(
"Due Time: %1\n",
timeToString( todo->dtDue(),
true, mSpec ) );
3843 QString details = todo->richDescription();
3844 if ( !details.isEmpty() ) {
3845 mResult += i18n(
"Details:\n%1\n", details );
3847 return !mResult.isEmpty();
3852 mResult = mailBodyIncidence( journal );
3853 mResult += i18n(
"Date: %1\n",
dateToString( journal->dtStart(),
true, mSpec ) );
3854 if ( !journal->allDay() ) {
3855 mResult += i18n(
"Time: %1\n",
timeToString( journal->dtStart(),
true, mSpec ) );
3857 if ( !journal->description().isEmpty() ) {
3858 mResult += i18n(
"Text of the journal:\n%1\n", journal->richDescription() );
3860 return !mResult.isEmpty();
3865 KDateTime::Spec spec )
3872 if ( v.act( incidence, spec ) ) {
3882 if ( incidence->allDay() ) {
3883 endstr = KGlobal::locale()->formatDate( incidence->recurrence()->endDate() );
3885 endstr = KGlobal::locale()->formatDateTime( incidence->recurrence()->endDateTime() );
3897 if ( !incidence->recurs() ) {
3898 return i18n(
"No recurrence" );
3900 static QStringList dayList;
3901 if ( dayList.isEmpty() ) {
3902 dayList.append( i18n(
"31st Last" ) );
3903 dayList.append( i18n(
"30th Last" ) );
3904 dayList.append( i18n(
"29th Last" ) );
3905 dayList.append( i18n(
"28th Last" ) );
3906 dayList.append( i18n(
"27th Last" ) );
3907 dayList.append( i18n(
"26th Last" ) );
3908 dayList.append( i18n(
"25th Last" ) );
3909 dayList.append( i18n(
"24th Last" ) );
3910 dayList.append( i18n(
"23rd Last" ) );
3911 dayList.append( i18n(
"22nd Last" ) );
3912 dayList.append( i18n(
"21st Last" ) );
3913 dayList.append( i18n(
"20th Last" ) );
3914 dayList.append( i18n(
"19th Last" ) );
3915 dayList.append( i18n(
"18th Last" ) );
3916 dayList.append( i18n(
"17th Last" ) );
3917 dayList.append( i18n(
"16th Last" ) );
3918 dayList.append( i18n(
"15th Last" ) );
3919 dayList.append( i18n(
"14th Last" ) );
3920 dayList.append( i18n(
"13th Last" ) );
3921 dayList.append( i18n(
"12th Last" ) );
3922 dayList.append( i18n(
"11th Last" ) );
3923 dayList.append( i18n(
"10th Last" ) );
3924 dayList.append( i18n(
"9th Last" ) );
3925 dayList.append( i18n(
"8th Last" ) );
3926 dayList.append( i18n(
"7th Last" ) );
3927 dayList.append( i18n(
"6th Last" ) );
3928 dayList.append( i18n(
"5th Last" ) );
3929 dayList.append( i18n(
"4th Last" ) );
3930 dayList.append( i18n(
"3rd Last" ) );
3931 dayList.append( i18n(
"2nd Last" ) );
3932 dayList.append( i18nc(
"last day of the month",
"Last" ) );
3933 dayList.append( i18nc(
"unknown day of the month",
"unknown" ) );
3934 dayList.append( i18n(
"1st" ) );
3935 dayList.append( i18n(
"2nd" ) );
3936 dayList.append( i18n(
"3rd" ) );
3937 dayList.append( i18n(
"4th" ) );
3938 dayList.append( i18n(
"5th" ) );
3939 dayList.append( i18n(
"6th" ) );
3940 dayList.append( i18n(
"7th" ) );
3941 dayList.append( i18n(
"8th" ) );
3942 dayList.append( i18n(
"9th" ) );
3943 dayList.append( i18n(
"10th" ) );
3944 dayList.append( i18n(
"11th" ) );
3945 dayList.append( i18n(
"12th" ) );
3946 dayList.append( i18n(
"13th" ) );
3947 dayList.append( i18n(
"14th" ) );
3948 dayList.append( i18n(
"15th" ) );
3949 dayList.append( i18n(
"16th" ) );
3950 dayList.append( i18n(
"17th" ) );
3951 dayList.append( i18n(
"18th" ) );
3952 dayList.append( i18n(
"19th" ) );
3953 dayList.append( i18n(
"20th" ) );
3954 dayList.append( i18n(
"21st" ) );
3955 dayList.append( i18n(
"22nd" ) );
3956 dayList.append( i18n(
"23rd" ) );
3957 dayList.append( i18n(
"24th" ) );
3958 dayList.append( i18n(
"25th" ) );
3959 dayList.append( i18n(
"26th" ) );
3960 dayList.append( i18n(
"27th" ) );
3961 dayList.append( i18n(
"28th" ) );
3962 dayList.append( i18n(
"29th" ) );
3963 dayList.append( i18n(
"30th" ) );
3964 dayList.append( i18n(
"31st" ) );
3967 const int weekStart = KGlobal::locale()->weekStartDay();
3969 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
3973 QString txt, recurStr;
3974 static QString noRecurrence = i18n(
"No recurrence" );
3976 case Recurrence::rNone:
3977 return noRecurrence;
3979 case Recurrence::rMinutely:
3981 recurStr = i18np(
"Recurs every minute until %2",
3982 "Recurs every %1 minutes until %2",
3983 recur->
frequency(), recurEnd( incidence ) );
3985 recurStr += i18nc(
"number of occurrences",
3986 " (<numid>%1</numid> occurrences)",
3990 recurStr = i18np(
"Recurs every minute",
3991 "Recurs every %1 minutes", recur->
frequency() );
3995 case Recurrence::rHourly:
3997 recurStr = i18np(
"Recurs hourly until %2",
3998 "Recurs every %1 hours until %2",
3999 recur->
frequency(), recurEnd( incidence ) );
4001 recurStr += i18nc(
"number of occurrences",
4002 " (<numid>%1</numid> occurrences)",
4006 recurStr = i18np(
"Recurs hourly",
"Recurs every %1 hours", recur->
frequency() );
4010 case Recurrence::rDaily:
4012 recurStr = i18np(
"Recurs daily until %2",
4013 "Recurs every %1 days until %2",
4014 recur->
frequency(), recurEnd( incidence ) );
4016 recurStr += i18nc(
"number of occurrences",
4017 " (<numid>%1</numid> occurrences)",
4021 recurStr = i18np(
"Recurs daily",
"Recurs every %1 days", recur->
frequency() );
4025 case Recurrence::rWeekly:
4027 bool addSpace =
false;
4028 for (
int i = 0; i < 7; ++i ) {
4029 if ( recur->
days().testBit( ( i + weekStart + 6 ) % 7 ) ) {
4031 dayNames.append( i18nc(
"separator for list of days",
", " ) );
4033 dayNames.append( calSys->weekDayName( ( ( i + weekStart + 6 ) % 7 ) + 1,
4034 KCalendarSystem::ShortDayName ) );
4038 if ( dayNames.isEmpty() ) {
4039 dayNames = i18nc(
"Recurs weekly on no days",
"no days" );
4042 recurStr = i18ncp(
"Recurs weekly on [list of days] until end-date",
4043 "Recurs weekly on %2 until %3",
4044 "Recurs every <numid>%1</numid> weeks on %2 until %3",
4045 recur->
frequency(), dayNames, recurEnd( incidence ) );
4047 recurStr += i18nc(
"number of occurrences",
4048 " (<numid>%1</numid> occurrences)",
4052 recurStr = i18ncp(
"Recurs weekly on [list of days]",
4053 "Recurs weekly on %2",
4054 "Recurs every <numid>%1</numid> weeks on %2",
4059 case Recurrence::rMonthlyPos:
4064 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...]"
4065 " weekdayname until end-date",
4066 "Recurs every month on the %2 %3 until %4",
4067 "Recurs every <numid>%1</numid> months on the %2 %3 until %4",
4069 dayList[rule.
pos() + 31],
4070 calSys->weekDayName( rule.
day(), KCalendarSystem::LongDayName ),
4071 recurEnd( incidence ) );
4073 recurStr += i18nc(
"number of occurrences",
4074 " (<numid>%1</numid> occurrences)",
4078 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...] weekdayname",
4079 "Recurs every month on the %2 %3",
4080 "Recurs every %1 months on the %2 %3",
4082 dayList[rule.
pos() + 31],
4083 calSys->weekDayName( rule.
day(), KCalendarSystem::LongDayName ) );
4088 case Recurrence::rMonthlyDay:
4093 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day until end-date",
4094 "Recurs monthly on the %2 day until %3",
4095 "Recurs every %1 months on the %2 day until %3",
4098 recurEnd( incidence ) );
4100 recurStr += i18nc(
"number of occurrences",
4101 " (<numid>%1</numid> occurrences)",
4105 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day",
4106 "Recurs monthly on the %2 day",
4107 "Recurs every <numid>%1</numid> month on the %2 day",
4109 dayList[days + 31] );
4114 case Recurrence::rYearlyMonth:
4118 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]"
4120 "Recurs yearly on %2 %3 until %4",
4121 "Recurs every %1 years on %2 %3 until %4",
4125 recurEnd( incidence ) );
4127 recurStr += i18nc(
"number of occurrences",
4128 " (<numid>%1</numid> occurrences)",
4134 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]",
4135 "Recurs yearly on %2 %3",
4136 "Recurs every %1 years on %2 %3",
4140 dayList[ recur->
yearDates()[0] + 31 ] );
4143 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4144 "Recurs yearly on %1 %2",
4147 dayList[ recur->
startDate().day() + 31 ] );
4149 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4150 "Recurs yearly on %1 %2",
4151 calSys->monthName( recur->
startDate().month(),
4153 dayList[ recur->
startDate().day() + 31 ] );
4159 case Recurrence::rYearlyDay:
4160 if ( !recur->
yearDays().isEmpty() ) {
4162 recurStr = i18ncp(
"Recurs every N years on day N until end-date",
4163 "Recurs every year on day <numid>%2</numid> until %3",
4164 "Recurs every <numid>%1</numid> years"
4165 " on day <numid>%2</numid> until %3",
4168 recurEnd( incidence ) );
4170 recurStr += i18nc(
"number of occurrences",
4171 " (<numid>%1</numid> occurrences)",
4175 recurStr = i18ncp(
"Recurs every N YEAR[S] on day N",
4176 "Recurs every year on day <numid>%2</numid>",
4177 "Recurs every <numid>%1</numid> years"
4178 " on day <numid>%2</numid>",
4183 case Recurrence::rYearlyPos:
4188 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4189 "of monthname until end-date",
4190 "Every year on the %2 %3 of %4 until %5",
4191 "Every <numid>%1</numid> years on the %2 %3 of %4"
4194 dayList[rule.
pos() + 31],
4195 calSys->weekDayName( rule.
day(), KCalendarSystem::LongDayName ),
4197 recurEnd( incidence ) );
4199 recurStr += i18nc(
"number of occurrences",
4200 " (<numid>%1</numid> occurrences)",
4204 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4206 "Every year on the %2 %3 of %4",
4207 "Every <numid>%1</numid> years on the %2 %3 of %4",
4209 dayList[rule.
pos() + 31],
4210 calSys->weekDayName( rule.
day(), KCalendarSystem::LongDayName ),
4218 if ( recurStr.isEmpty() ) {
4219 recurStr = i18n(
"Incidence recurs" );
4224 DateTimeList::ConstIterator il;
4226 for ( il = l.constBegin(); il != l.constEnd(); ++il ) {
4228 case Recurrence::rMinutely:
4229 exStr << i18n(
"minute %1", (*il).time().minute() );
4231 case Recurrence::rHourly:
4232 exStr << KGlobal::locale()->formatTime( (*il).time() );
4234 case Recurrence::rDaily:
4235 exStr << KGlobal::locale()->formatDate( (*il).date(), KLocale::ShortDate );
4237 case Recurrence::rWeekly:
4238 exStr << calSys->weekDayName( (*il).date(), KCalendarSystem::ShortDayName );
4240 case Recurrence::rMonthlyPos:
4241 exStr << KGlobal::locale()->formatDate( (*il).date(), KLocale::ShortDate );
4243 case Recurrence::rMonthlyDay:
4244 exStr << KGlobal::locale()->formatDate( (*il).date(), KLocale::ShortDate );
4246 case Recurrence::rYearlyMonth:
4247 exStr << calSys->monthName( (*il).date(), KCalendarSystem::LongName );
4249 case Recurrence::rYearlyDay:
4250 exStr << KGlobal::locale()->formatDate( (*il).date(), KLocale::ShortDate );
4252 case Recurrence::rYearlyPos:
4253 exStr << KGlobal::locale()->formatDate( (*il).date(), KLocale::ShortDate );
4259 DateList::ConstIterator dl;
4260 for ( dl = d.constBegin(); dl != d.constEnd(); ++dl ) {
4262 case Recurrence::rDaily:
4263 exStr << KGlobal::locale()->formatDate( (*dl), KLocale::ShortDate );
4265 case Recurrence::rWeekly:
4268 if ( exStr.isEmpty() ) {
4269 exStr << i18np(
"1 day",
"%1 days", recur->
exDates().count() );
4272 case Recurrence::rMonthlyPos:
4273 exStr << KGlobal::locale()->formatDate( (*dl), KLocale::ShortDate );
4275 case Recurrence::rMonthlyDay:
4276 exStr << KGlobal::locale()->formatDate( (*dl), KLocale::ShortDate );
4278 case Recurrence::rYearlyMonth:
4279 exStr << calSys->monthName( (*dl), KCalendarSystem::LongName );
4281 case Recurrence::rYearlyDay:
4282 exStr << KGlobal::locale()->formatDate( (*dl), KLocale::ShortDate );
4284 case Recurrence::rYearlyPos:
4285 exStr << KGlobal::locale()->formatDate( (*dl), KLocale::ShortDate );
4290 if ( !exStr.isEmpty() ) {
4291 recurStr = i18n(
"%1 (excluding %2)", recurStr, exStr.join(
"," ) );
4299 const KDateTime::Spec &spec )
4301 if ( spec.isValid() ) {
4304 if ( spec.timeZone() != KSystemTimeZones::local() ) {
4305 timeZone =
' ' + spec.timeZone().name();
4308 return KGlobal::locale()->formatTime( date.toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
4310 return KGlobal::locale()->formatTime( date.time(), !shortfmt );
4316 const KDateTime::Spec &spec )
4318 if ( spec.isValid() ) {
4321 if ( spec.timeZone() != KSystemTimeZones::local() ) {
4322 timeZone =
' ' + spec.timeZone().name();
4326 KGlobal::locale()->formatDate( date.toTimeSpec( spec ).date(),
4327 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) +
4331 KGlobal::locale()->formatDate( date.date(),
4332 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
4339 const KDateTime::Spec &spec )
4345 if ( spec.isValid() ) {
4347 if ( spec.timeZone() != KSystemTimeZones::local() ) {
4348 timeZone =
' ' + spec.timeZone().name();
4351 return KGlobal::locale()->formatDateTime(
4352 date.toTimeSpec( spec ).dateTime(),
4353 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
4355 return KGlobal::locale()->formatDateTime(
4357 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
4364 Q_UNUSED( calendar );
4365 Q_UNUSED( incidence );
4369 static QString secs2Duration(
int secs )
4372 int days = secs / 86400;
4374 tmp += i18np(
"1 day",
"%1 days", days );
4376 secs -= ( days * 86400 );
4378 int hours = secs / 3600;
4380 tmp += i18np(
"1 hour",
"%1 hours", hours );
4382 secs -= ( hours * 3600 );
4384 int mins = secs / 60;
4386 tmp += i18np(
"1 minute",
"%1 minutes", mins );
4394 if ( incidence->type() == Incidence::TypeEvent ) {
4396 if ( event->hasEndDate() ) {
4397 if ( !event->allDay() ) {
4398 tmp = secs2Duration( event->dtStart().secsTo( event->dtEnd() ) );
4400 tmp = i18np(
"1 day",
"%1 days",
4401 event->dtStart().date().daysTo( event->dtEnd().date() ) + 1 );
4404 tmp = i18n(
"forever" );
4406 }
else if ( incidence->type() == Incidence::TypeTodo ) {
4408 if ( todo->hasDueDate() ) {
4409 if ( todo->hasStartDate() ) {
4410 if ( !todo->allDay() ) {
4411 tmp = secs2Duration( todo->dtStart().secsTo( todo->dtDue() ) );
4413 tmp = i18np(
"1 day",
"%1 days",
4414 todo->dtStart().date().daysTo( todo->dtDue().date() ) + 1 );
4426 Q_UNUSED( shortfmt );
4432 Alarm::List::ConstIterator it;
4433 for ( it = alarms.constBegin(); it != alarms.constEnd(); ++it ) {
4436 QString remStr, atStr, offsetStr;
4437 if ( alarm->hasTime() ) {
4439 if ( alarm->time().isValid() ) {
4440 atStr = KGlobal::locale()->formatDateTime( alarm->time() );
4442 }
else if ( alarm->hasStartOffset() ) {
4443 offset = alarm->startOffset().asSeconds();
4446 offsetStr = i18nc(
"N days/hours/minutes before the start datetime",
4447 "%1 before the start", secs2Duration( offset ) );
4448 }
else if ( offset > 0 ) {
4449 offsetStr = i18nc(
"N days/hours/minutes after the start datetime",
4450 "%1 after the start", secs2Duration( offset ) );
4452 if ( incidence->dtStart().isValid() ) {
4453 atStr = KGlobal::locale()->formatDateTime( incidence->dtStart() );
4456 }
else if ( alarm->hasEndOffset() ) {
4457 offset = alarm->endOffset().asSeconds();
4460 if ( incidence->type() == Incidence::TypeTodo ) {
4461 offsetStr = i18nc(
"N days/hours/minutes before the due datetime",
4462 "%1 before the to-do is due", secs2Duration( offset ) );
4464 offsetStr = i18nc(
"N days/hours/minutes before the end datetime",
4465 "%1 before the end", secs2Duration( offset ) );
4467 }
else if ( offset > 0 ) {
4468 if ( incidence->type() == Incidence::TypeTodo ) {
4469 offsetStr = i18nc(
"N days/hours/minutes after the due datetime",
4470 "%1 after the to-do is due", secs2Duration( offset ) );
4472 offsetStr = i18nc(
"N days/hours/minutes after the end datetime",
4473 "%1 after the end", secs2Duration( offset ) );
4476 if ( incidence->type() == Incidence::TypeTodo ) {
4478 if ( t->dtDue().isValid() ) {
4479 atStr = KGlobal::locale()->formatDateTime( t->dtDue() );
4483 if ( e->dtEnd().isValid() ) {
4484 atStr = KGlobal::locale()->formatDateTime( e->dtEnd() );
4489 if ( offset == 0 ) {
4490 if ( !atStr.isEmpty() ) {
4491 remStr = i18nc(
"reminder occurs at datetime",
"at %1", atStr );
4497 if ( alarm->repeatCount() > 0 ) {
4498 QString countStr = i18np(
"repeats once",
"repeats %1 times", alarm->repeatCount() );
4499 QString intervalStr = i18nc(
"interval is N days/hours/minutes",
4501 secs2Duration( alarm->snoozeTime().asSeconds() ) );
4502 QString repeatStr = i18nc(
"(repeat string, interval string)",
4503 "(%1, %2)", countStr, intervalStr );
4504 remStr = remStr +
' ' + repeatStr;
4507 reminderStringList << remStr;