41 #ifndef KDEPIM_NO_KRESOURCES
50 #include "kpimutils/email.h"
51 #include "kabc/phonenumber.h"
52 #include "kabc/vcardconverter.h"
53 #include "kabc/stdaddressbook.h"
55 #include <kdatetime.h>
56 #include <kemailsettings.h>
59 #include <kiconloader.h>
60 #include <klocalizedstring.h>
61 #include <kcalendarsystem.h>
62 #include <ksystemtimezone.h>
63 #include <kmimetype.h>
65 #include <QtCore/QBuffer>
66 #include <QtCore/QList>
67 #include <QTextDocument>
68 #include <QApplication>
71 using namespace IncidenceFormatter;
78 static QString htmlAddLink(
const QString &ref,
const QString &text,
81 QString tmpStr(
"<a href=\"" + ref +
"\">" + text +
"</a>" );
88 static QString htmlAddTag(
const QString &tag,
const QString &text )
90 int numLineBreaks = text.count(
"\n" );
91 QString str =
'<' + tag +
'>';
92 QString tmpText = text;
94 if( numLineBreaks >= 0 ) {
95 if ( numLineBreaks > 0 ) {
98 for (
int i = 0; i <= numLineBreaks; ++i ) {
99 pos = tmpText.indexOf(
"\n" );
100 tmp = tmpText.left( pos );
101 tmpText = tmpText.right( tmpText.length() - pos - 1 );
102 tmpStr += tmp +
"<br>";
108 tmpStr +=
"</" + tag +
'>';
112 static bool iamAttendee(
Attendee *attendee )
117 KEMailSettings settings;
118 QStringList profiles = settings.profiles();
119 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
120 settings.setProfile( *it );
121 if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->
email() ) {
129 static bool iamOrganizer(
Incidence *incidence )
138 KEMailSettings settings;
139 QStringList profiles = settings.profiles();
140 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
141 settings.setProfile( *it );
142 if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->
organizer().
email() ) {
150 static bool senderIsOrganizer(
Incidence *incidence,
const QString &sender )
154 if ( !incidence || sender.isEmpty() ) {
159 QString senderName, senderEmail;
160 if ( KPIMUtils::extractEmailAddressAndName( sender, senderEmail, senderName ) ) {
170 static QString firstAttendeeName(
Incidence *incidence,
const QString &defName )
178 if( attendees.count() > 0 ) {
179 Attendee *attendee = *attendees.begin();
180 name = attendee->
name();
181 if ( name.isEmpty() ) {
182 name = attendee->
email();
184 if ( name.isEmpty() ) {
197 static QString displayViewLinkPerson(
const QString &email, QString name,
198 QString uid,
const QString &iconPath )
202 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
203 #ifndef KDEPIM_NO_KRESOURCES
204 KABC::AddressBook *add_book = KABC::StdAddressBook::self(
true );
205 KABC::Addressee::List addressList = add_book->findByEmail( email );
206 KABC::Addressee o = ( !addressList.isEmpty() ? addressList.first() : KABC::Addressee() );
207 if ( !o.isEmpty() && addressList.size() < 2 ) {
208 if ( name.isEmpty() ) {
210 name = o.formattedName();
224 if ( !uid.isEmpty() ) {
226 if ( name.isEmpty() ) {
228 tmpString += htmlAddLink(
"uid:" + uid, email );
230 tmpString += htmlAddLink(
"uid:" + uid, name );
234 tmpString += ( name.isEmpty() ? email : name );
238 if ( !email.isEmpty() && !iconPath.isNull() ) {
240 mailto.setProtocol(
"mailto" );
241 mailto.setPath( email );
242 tmpString += htmlAddLink( mailto.url(),
243 "<img valign=\"top\" src=\"" + iconPath +
"\">" );
252 Attendee::List::ConstIterator it;
254 KIconLoader *iconLoader = KIconLoader::global();
255 const QString iconPath = iconLoader->iconPath(
"mail-message-new", KIconLoader::Small );
257 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
259 if ( a->
role() != role ) {
267 tmpStr += displayViewLinkPerson( a->
email(), a->
name(), a->
uid(), iconPath );
269 tmpStr += i18n(
" (delegated by %1)", a->
delegator() );
272 tmpStr += i18n(
" (delegated to %1)", a->
delegate() );
276 if ( tmpStr.endsWith( QLatin1String(
"<br>" ) ) ) {
282 static QString displayViewFormatAttendees(
Incidence *incidence )
286 KIconLoader *iconLoader = KIconLoader::global();
287 const QString iconPath = iconLoader->iconPath(
"mail-message-new", KIconLoader::Small );
290 int attendeeCount = incidence->
attendees().count();
291 if ( attendeeCount > 1 ||
292 ( attendeeCount == 1 &&
295 tmpStr +=
"<td><b>" + i18n(
"Organizer:" ) +
"</b></td>";
299 QString(), iconPath ) +
306 if ( !str.isEmpty() ) {
308 tmpStr +=
"<td><b>" + i18n(
"Chair:" ) +
"</b></td>";
309 tmpStr +=
"<td>" + str +
"</td>";
315 if ( !str.isEmpty() ) {
317 tmpStr +=
"<td><b>" + i18n(
"Required Participants:" ) +
"</b></td>";
318 tmpStr +=
"<td>" + str +
"</td>";
324 if ( !str.isEmpty() ) {
326 tmpStr +=
"<td><b>" + i18n(
"Optional Participants:" ) +
"</b></td>";
327 tmpStr +=
"<td>" + str +
"</td>";
333 if ( !str.isEmpty() ) {
335 tmpStr +=
"<td><b>" + i18n(
"Observers:" ) +
"</b></td>";
336 tmpStr +=
"<td>" + str +
"</td>";
343 static QString displayViewFormatAttachments(
Incidence *incidence )
347 Attachment::List::ConstIterator it;
349 for ( it = as.constBegin(); it != as.constEnd(); ++it ) {
351 if ( (*it)->isUri() ) {
353 if ( (*it)->uri().startsWith( QLatin1String(
"kmail:" ) ) ) {
354 name = i18n(
"Show mail" );
356 name = (*it)->label();
358 tmpStr += htmlAddLink( (*it)->uri(), name );
360 tmpStr += (*it)->label();
362 if ( count < as.count() ) {
369 static QString displayViewFormatCategories(
Incidence *incidence )
375 static QString displayViewFormatCreationDate(
Incidence *incidence, KDateTime::Spec spec )
377 KDateTime kdt = incidence->
created().toTimeSpec( spec );
381 static QString displayViewFormatBirthday(
Event *event )
387 event->customProperty(
"KABC",
"ANNIVERSARY" ) !=
"YES" ) {
391 QString uid_1 =
event->customProperty(
"KABC",
"UID-1" );
392 QString name_1 =
event->customProperty(
"KABC",
"NAME-1" );
393 QString email_1=
event->customProperty(
"KABC",
"EMAIL-1" );
395 KIconLoader *iconLoader = KIconLoader::global();
396 const QString iconPath = iconLoader->iconPath(
"mail-message-new", KIconLoader::Small );
398 QString tmpStr = displayViewLinkPerson( email_1, name_1, uid_1, iconPath );
403 static QString displayViewFormatHeader(
Incidence *incidence )
405 QString tmpStr =
"<table><tr>";
408 KIconLoader *iconLoader = KIconLoader::global();
414 if ( incidence->
type() ==
"Todo" ) {
415 tmpStr +=
"<img valign=\"top\" src=\"";
416 Todo *todo =
static_cast<Todo *
>( incidence );
418 tmpStr += iconLoader->iconPath(
"view-calendar-tasks", KIconLoader::Small );
420 tmpStr += iconLoader->iconPath(
"task-complete", KIconLoader::Small );
425 if ( incidence->
type() ==
"Event" ) {
428 iconPath = iconLoader->iconPath(
"view-calendar-birthday", KIconLoader::Small );
429 }
else if ( incidence->
customProperty(
"KABC",
"ANNIVERSARY" ) ==
"YES" ) {
430 iconPath = iconLoader->iconPath(
"view-calendar-wedding-anniversary", KIconLoader::Small );
432 iconPath = iconLoader->iconPath(
"view-calendar-day", KIconLoader::Small );
434 tmpStr +=
"<img valign=\"top\" src=\"" + iconPath +
"\">";
437 if ( incidence->
type() ==
"Journal" ) {
438 tmpStr +=
"<img valign=\"top\" src=\"" +
439 iconLoader->iconPath(
"view-pim-journal", KIconLoader::Small ) +
444 tmpStr +=
"<img valign=\"top\" src=\"" +
445 iconLoader->iconPath(
"preferences-desktop-notification-bell", KIconLoader::Small ) +
448 if ( incidence->
recurs() ) {
449 tmpStr +=
"<img valign=\"top\" src=\"" +
450 iconLoader->iconPath(
"edit-redo", KIconLoader::Small ) +
454 tmpStr +=
"<img valign=\"top\" src=\"" +
455 iconLoader->iconPath(
"object-locked", KIconLoader::Small ) +
461 tmpStr +=
"<b><u>" + incidence->
richSummary() +
"</u></b>";
464 tmpStr +=
"</tr></table>";
469 static QString displayViewFormatEvent(
const QString &calStr,
Event *event,
470 const QDate &date, KDateTime::Spec spec )
476 QString tmpStr = displayViewFormatHeader( event );
479 tmpStr +=
"<col width=\"25%\"/>";
480 tmpStr +=
"<col width=\"75%\"/>";
482 if ( !calStr.isEmpty() ) {
484 tmpStr +=
"<td><b>" + i18n(
"Calendar:" ) +
"</b></td>";
485 tmpStr +=
"<td>" + calStr +
"</td>";
489 if ( !event->
location().isEmpty() ) {
491 tmpStr +=
"<td><b>" + i18nc(
"@title:column event location",
"Location:" ) +
"</b></td>";
492 tmpStr +=
"<td>" +
event->richLocation() +
"</td>";
496 KDateTime startDt =
event->dtStart();
497 KDateTime endDt =
event->dtEnd();
499 if ( date.isValid() ) {
500 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
501 int diffDays = startDt.daysTo( kdt );
502 kdt = kdt.addSecs( -1 );
505 endDt = endDt.addDays( diffDays );
506 if ( startDt > endDt ) {
508 endDt = startDt.addDays( event->
dtStart().daysTo( event->
dtEnd() ) );
517 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
519 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
524 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
526 i18nc(
"date as string",
"%1",
532 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
534 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
539 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
541 i18nc(
"date as string",
"%1",
545 tmpStr +=
"</tr><tr>";
546 tmpStr +=
"<td><b>" + i18n(
"Time:" ) +
"</b></td>";
547 if ( event->
hasEndDate() && startDt != endDt ) {
549 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
563 if ( !durStr.isEmpty() ) {
565 tmpStr +=
"<td><b>" + i18n(
"Duration:" ) +
"</b></td>";
566 tmpStr +=
"<td>" + durStr +
"</td>";
572 tmpStr +=
"<td><b>" + i18n(
"Recurrence:" ) +
"</b></td>";
579 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY" ) ==
"YES";
580 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY" ) ==
"YES";
582 if ( isBirthday || isAnniversary ) {
584 if ( isAnniversary ) {
585 tmpStr +=
"<td><b>" + i18n(
"Anniversary:" ) +
"</b></td>";
587 tmpStr +=
"<td><b>" + i18n(
"Birthday:" ) +
"</b></td>";
589 tmpStr +=
"<td>" + displayViewFormatBirthday( event ) +
"</td>";
591 tmpStr +=
"</table>";
597 tmpStr +=
"<td><b>" + i18n(
"Description:" ) +
"</b></td>";
598 tmpStr +=
"<td>" +
event->richDescription() +
"</td>";
604 int reminderCount =
event->alarms().count();
607 tmpStr +=
"<td><b>" +
608 i18np(
"Reminder:",
"Reminders:", reminderCount ) +
614 tmpStr += displayViewFormatAttendees( event );
616 int categoryCount =
event->categories().count();
617 if ( categoryCount > 0 ) {
620 tmpStr += i18np(
"Category:",
"Categories:", categoryCount ) +
622 tmpStr +=
"<td>" + displayViewFormatCategories( event ) +
"</td>";
626 int attachmentCount =
event->attachments().count();
627 if ( attachmentCount > 0 ) {
629 tmpStr +=
"<td><b>" +
630 i18np(
"Attachment:",
"Attachments:", attachmentCount ) +
632 tmpStr +=
"<td>" + displayViewFormatAttachments( event ) +
"</td>";
635 tmpStr +=
"</table>";
637 tmpStr +=
"<p><em>" + displayViewFormatCreationDate( event, spec ) +
"</em>";
642 static QString displayViewFormatTodo(
const QString &calStr,
Todo *todo,
643 const QDate &date, KDateTime::Spec spec )
649 QString tmpStr = displayViewFormatHeader( todo );
652 tmpStr +=
"<col width=\"25%\"/>";
653 tmpStr +=
"<col width=\"75%\"/>";
655 if ( !calStr.isEmpty() ) {
657 tmpStr +=
"<td><b>" + i18n(
"Calendar:" ) +
"</b></td>";
658 tmpStr +=
"<td>" + calStr +
"</td>";
662 if ( !todo->
location().isEmpty() ) {
664 tmpStr +=
"<td><b>" + i18nc(
"@title:column to-do location",
"Location:" ) +
"</b></td>";
670 KDateTime startDt = todo->
dtStart();
672 if ( date.isValid() ) {
673 startDt.setDate( date );
677 tmpStr +=
"<td><b>" +
678 i18nc(
"to-do start date/time",
"Start:" ) +
687 KDateTime dueDt = todo->
dtDue();
689 if ( date.isValid() ) {
690 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
691 kdt = kdt.addSecs( -1 );
696 tmpStr +=
"<td><b>" +
697 i18nc(
"to-do due date/time",
"Due:" ) +
706 if ( !durStr.isEmpty() ) {
708 tmpStr +=
"<td><b>" + i18n(
"Duration:" ) +
"</b></td>";
709 tmpStr +=
"<td>" + durStr +
"</td>";
715 tmpStr +=
"<td><b>" + i18n(
"Recurrence:" ) +
"</b></td>";
724 tmpStr +=
"<td><b>" + i18n(
"Description:" ) +
"</b></td>";
731 int reminderCount = todo->
alarms().count();
734 tmpStr +=
"<td><b>" +
735 i18np(
"Reminder:",
"Reminders:", reminderCount ) +
741 tmpStr += displayViewFormatAttendees( todo );
743 int categoryCount = todo->
categories().count();
744 if ( categoryCount > 0 ) {
746 tmpStr +=
"<td><b>" +
747 i18np(
"Category:",
"Categories:", categoryCount ) +
749 tmpStr +=
"<td>" + displayViewFormatCategories( todo ) +
"</td>";
755 tmpStr +=
"<td><b>" + i18n(
"Priority:" ) +
"</b></td>";
757 tmpStr += QString::number( todo->
priority() );
764 tmpStr +=
"<td><b>" + i18nc(
"Completed: date",
"Completed:" ) +
"</b></td>";
768 tmpStr +=
"<td><b>" + i18n(
"Percent Done:" ) +
"</b></td>";
776 if ( attachmentCount > 0 ) {
778 tmpStr +=
"<td><b>" +
779 i18np(
"Attachment:",
"Attachments:", attachmentCount ) +
781 tmpStr +=
"<td>" + displayViewFormatAttachments( todo ) +
"</td>";
784 tmpStr +=
"</table>";
786 tmpStr +=
"<p><em>" + displayViewFormatCreationDate( todo, spec ) +
"</em>";
791 static QString displayViewFormatJournal(
const QString &calStr,
Journal *journal,
792 KDateTime::Spec spec )
798 QString tmpStr = displayViewFormatHeader( journal );
801 tmpStr +=
"<col width=\"25%\"/>";
802 tmpStr +=
"<col width=\"75%\"/>";
804 if ( !calStr.isEmpty() ) {
806 tmpStr +=
"<td><b>" + i18n(
"Calendar:" ) +
"</b></td>";
807 tmpStr +=
"<td>" + calStr +
"</td>";
812 tmpStr +=
"<td><b>" + i18n(
"Date:" ) +
"</b></td>";
820 tmpStr +=
"<td><b>" + i18n(
"Description:" ) +
"</b></td>";
825 int categoryCount = journal->
categories().count();
826 if ( categoryCount > 0 ) {
828 tmpStr +=
"<td><b>" +
829 i18np(
"Category:",
"Categories:", categoryCount ) +
831 tmpStr +=
"<td>" + displayViewFormatCategories( journal ) +
"</td>";
835 tmpStr +=
"</table>";
837 tmpStr +=
"<p><em>" + displayViewFormatCreationDate( journal, spec ) +
"</em>";
842 static QString displayViewFormatFreeBusy(
const QString &calStr,
FreeBusy *fb,
843 KDateTime::Spec spec )
854 tmpStr += htmlAddTag(
"h4",
855 i18n(
"Busy times in date range %1 - %2:",
863 htmlAddTag(
"b", i18nc(
"tag for busy periods list",
"Busy:" ) ) );
865 QList<Period>::iterator it;
866 for ( it = periods.begin(); it != periods.end(); ++it ) {
872 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600 );
876 cont += i18ncp(
"minutes part duration",
"1 minute ",
"%1 minutes ", dur / 60 );
880 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur );
882 text += i18nc(
"startDate for duration",
"%1 for %2",
887 if ( per.
start().date() == per.
end().date() ) {
888 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
893 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
900 tmpStr += htmlAddTag(
"p", text );
906 class KCal::IncidenceFormatter::EventViewerVisitor
911 : mCalendar( 0 ), mSpec( KDateTime::Spec() ), mResult(
"" ) {}
914 KDateTime::Spec spec=KDateTime::Spec() )
916 mCalendar = calendar;
921 return incidence->
accept( *
this );
924 bool act(
const QString &sourceName,
IncidenceBase *incidence,
const QDate &date,
925 KDateTime::Spec spec=KDateTime::Spec() )
928 mSourceName = sourceName;
932 return incidence->
accept( *
this );
935 QString result()
const {
return mResult; }
940 const QString calStr = mCalendar ?
resourceString( mCalendar, event ) : mSourceName;
941 mResult = displayViewFormatEvent( calStr, event, mDate, mSpec );
942 return !mResult.isEmpty();
946 const QString calStr = mCalendar ?
resourceString( mCalendar, todo ) : mSourceName;
947 mResult = displayViewFormatTodo( calStr, todo, mDate, mSpec );
948 return !mResult.isEmpty();
952 const QString calStr = mCalendar ?
resourceString( mCalendar, journal ) : mSourceName;
953 mResult = displayViewFormatJournal( calStr, journal, mSpec );
954 return !mResult.isEmpty();
958 mResult = displayViewFormatFreeBusy( mSourceName, fb, mSpec );
959 return !mResult.isEmpty();
966 KDateTime::Spec mSpec;
977 KDateTime::Spec spec )
983 EventViewerVisitor v;
984 if ( v.act( 0, incidence, QDate(), spec ) ) {
994 KDateTime::Spec spec )
1000 EventViewerVisitor v;
1001 if ( v.act( calendar, incidence, date, spec ) ) {
1011 KDateTime::Spec spec )
1017 EventViewerVisitor v;
1018 if ( v.act( sourceName, incidence, date, spec ) ) {
1029 static QString string2HTML(
const QString &str )
1031 return Qt::convertFromPlainText( str, Qt::WhiteSpaceNormal );
1034 static QString cleanHtml(
const QString &html )
1036 QRegExp rx(
"<body[^>]*>(.*)</body>", Qt::CaseInsensitive );
1038 QString body = rx.cap( 1 );
1040 return Qt::escape( body.remove( QRegExp(
"<[^>]*>" ) ).trimmed() );
1043 static QString eventStartTimeStr(
Event *event )
1046 if ( !event->
allDay() ) {
1047 tmp = i18nc(
"%1: Start Date, %2: Start Time",
"%1 %2",
1051 tmp = i18nc(
"%1: Start Date",
"%1 (all day)",
1057 static QString eventEndTimeStr(
Event *event )
1060 if ( event->
hasEndDate() &&
event->dtEnd().isValid() ) {
1061 if ( !event->
allDay() ) {
1062 tmp = i18nc(
"%1: End Date, %2: End Time",
"%1 %2",
1066 tmp = i18nc(
"%1: End Date",
"%1 (all day)",
1073 static QString invitationRow(
const QString &cell1,
const QString &cell2 )
1075 return "<tr><td>" + cell1 +
"</td><td>" + cell2 +
"</td></tr>\n";
1087 KEMailSettings settings;
1088 QStringList profiles = settings.profiles();
1089 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
1090 settings.setProfile( *it );
1092 QString delegatorName, delegatorEmail;
1094 Attendee::List::ConstIterator it2;
1095 for ( it2 = attendees.constBegin(); it2 != attendees.constEnd(); ++it2 ) {
1097 KPIMUtils::extractEmailAddressAndName( a->
delegator(), delegatorEmail, delegatorName );
1098 if ( settings.getSetting( KEMailSettings::EmailAddress ) == delegatorEmail ) {
1116 KEMailSettings settings;
1117 QStringList profiles = settings.profiles();
1118 for ( QStringList::Iterator it=profiles.begin(); it != profiles.end(); ++it ) {
1119 settings.setProfile( *it );
1122 Attendee::List::ConstIterator it2;
1123 for ( it2 = attendees.constBegin(); it2 != attendees.constEnd(); ++it2 ) {
1125 if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->
email() ) {
1144 Attendee::List::ConstIterator it;
1145 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
1147 if ( email == a->
email() ) {
1155 static bool rsvpRequested(
Incidence *incidence )
1165 Attendee::List::ConstIterator it;
1166 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
1167 if ( it == attendees.constBegin() ) {
1168 rsvp = (*it)->RSVP();
1170 if ( (*it)->RSVP() != rsvp ) {
1179 static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role )
1181 if ( rsvpRequested ) {
1182 if ( role.isEmpty() ) {
1183 return i18n(
"Your response is requested" );
1185 return i18n(
"Your response as <b>%1</b> is requested", role );
1188 if ( role.isEmpty() ) {
1189 return i18n(
"No response is necessary" );
1191 return i18n(
"No response as <b>%1</b> is necessary", role );
1196 static QString myStatusStr(
Incidence *incidence )
1199 Attendee *a = findMyAttendee( incidence );
1202 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1208 static QString invitationPerson(
const QString &email, QString name, QString uid )
1212 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
1213 #ifndef KDEPIM_NO_KRESOURCES
1214 KABC::AddressBook *add_book = KABC::StdAddressBook::self(
true );
1215 KABC::Addressee::List addressList = add_book->findByEmail( email );
1216 if ( !addressList.isEmpty() ) {
1217 KABC::Addressee o = addressList.first();
1218 if ( !o.isEmpty() && addressList.size() < 2 ) {
1219 if ( name.isEmpty() ) {
1221 name = o.formattedName();
1236 if ( !uid.isEmpty() ) {
1238 if ( name.isEmpty() ) {
1240 tmpString += htmlAddLink(
"uid:" + uid, email );
1242 tmpString += htmlAddLink(
"uid:" + uid, name );
1246 tmpString += ( name.isEmpty() ? email : name );
1251 if ( !email.isEmpty() ) {
1254 mailto.setProtocol(
"mailto" );
1255 mailto.setPath( person.fullName() );
1256 const QString iconPath =
1257 KIconLoader::global()->iconPath(
"mail-message-new", KIconLoader::Small );
1258 tmpString += htmlAddLink( mailto.url(),
1259 "<img valign=\"top\" src=\"" + iconPath +
"\">" );
1266 static QString invitationsDetailsIncidence(
Incidence *incidence,
bool noHtmlMode )
1274 QStringList comments;
1276 if ( incidence->
comments().isEmpty() ) {
1280 comments << string2HTML( incidence->
description() );
1284 comments[0] = cleanHtml( comments[0] );
1286 comments[0] = htmlAddTag(
"p", comments[0] );
1292 foreach (
const QString &c, incidence->
comments() ) {
1293 if ( !c.isEmpty() ) {
1295 if ( !Qt::mightBeRichText( c ) ) {
1296 comments << string2HTML( c );
1299 comments << cleanHtml( cleanHtml(
"<body>" + c +
"</body>" ) );
1313 descr = cleanHtml( descr );
1315 descr = htmlAddTag(
"p", descr );
1320 if( !descr.isEmpty() ) {
1322 html +=
"<table border=\"0\" style=\"margin-top:4px;\">";
1323 html +=
"<tr><td><center>" +
1324 htmlAddTag(
"u", i18n(
"Description:" ) ) +
1325 "</center></td></tr>";
1326 html +=
"<tr><td>" + descr +
"</td></tr>";
1330 if ( !comments.isEmpty() ) {
1332 html +=
"<table border=\"0\" style=\"margin-top:4px;\">";
1333 html +=
"<tr><td><center>" +
1334 htmlAddTag(
"u", i18n(
"Comments:" ) ) +
1335 "</center></td></tr>";
1337 if ( comments.count() > 1 ) {
1339 for (
int i=0; i < comments.count(); ++i ) {
1340 html +=
"<li>" + comments[i] +
"</li>";
1344 html += comments[0];
1346 html +=
"</td></tr>";
1352 static QString invitationDetailsEvent(
Event *event,
bool noHtmlMode, KDateTime::Spec spec )
1359 QString sSummary = i18n(
"Summary unspecified" );
1360 if ( !event->
summary().isEmpty() ) {
1362 sSummary = Qt::escape( event->
summary() );
1364 sSummary =
event->richSummary();
1366 sSummary = cleanHtml( sSummary );
1371 QString sLocation = i18nc(
"event location",
"Location unspecified" );
1372 if ( !event->
location().isEmpty() ) {
1374 sLocation = Qt::escape( event->
location() );
1376 sLocation =
event->richLocation();
1378 sLocation = cleanHtml( sLocation );
1383 QString dir = ( QApplication::isRightToLeft() ?
"rtl" :
"ltr" );
1384 QString html = QString(
"<div dir=\"%1\">\n" ).arg( dir );
1385 html +=
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">";
1388 html += invitationRow( i18n(
"What:" ), sSummary );
1389 html += invitationRow( i18n(
"Where:" ), sLocation );
1392 if ( event->
dtStart().date() ==
event->dtEnd().date() ) {
1394 if ( !event->
allDay() ) {
1395 html += invitationRow( i18n(
"Time:" ),
1401 html += invitationRow( i18nc(
"starting date",
"From:" ),
1403 if ( !event->
allDay() ) {
1404 html += invitationRow( i18nc(
"starting time",
"At:" ),
1408 html += invitationRow( i18nc(
"ending date",
"To:" ),
1410 if ( !event->
allDay() ) {
1411 html += invitationRow( i18nc(
"ending time",
"At:" ),
1415 html += invitationRow( i18nc(
"ending date",
"To:" ),
1416 i18n(
"no end date specified" ) );
1422 if ( !durStr.isEmpty() ) {
1423 html += invitationRow( i18n(
"Duration:" ), durStr );
1430 html +=
"</table></div>\n";
1431 html += invitationsDetailsIncidence( event, noHtmlMode );
1436 static QString invitationDetailsTodo(
Todo *todo,
bool noHtmlMode, KDateTime::Spec spec )
1443 QString sSummary = i18n(
"Summary unspecified" );
1444 if ( !todo->
summary().isEmpty() ) {
1446 sSummary = Qt::escape( todo->
summary() );
1450 sSummary = cleanHtml( sSummary );
1455 QString sLocation = i18nc(
"todo location",
"Location unspecified" );
1456 if ( !todo->
location().isEmpty() ) {
1458 sLocation = Qt::escape( todo->
location() );
1462 sLocation = cleanHtml( sLocation );
1467 QString dir = ( QApplication::isRightToLeft() ?
"rtl" :
"ltr" );
1468 QString html = QString(
"<div dir=\"%1\">\n" ).arg( dir );
1469 html +=
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">";
1472 html += invitationRow( i18n(
"What:" ), sSummary );
1473 html += invitationRow( i18n(
"Where:" ), sLocation );
1476 html += invitationRow( i18n(
"Start Date:" ),
dateToString( todo->
dtStart(),
false, spec ) );
1478 html += invitationRow( i18n(
"Start Time:" ),
timeToString( todo->
dtStart(),
false, spec ) );
1482 html += invitationRow( i18n(
"Due Date:" ),
dateToString( todo->
dtDue(),
false, spec ) );
1484 html += invitationRow( i18n(
"Due Time:" ),
timeToString( todo->
dtDue(),
false, spec ) );
1487 html += invitationRow( i18n(
"Due Date:" ), i18nc(
"no to-do due date",
"None" ) );
1490 html +=
"</table></div>\n";
1491 html += invitationsDetailsIncidence( todo, noHtmlMode );
1496 static QString invitationDetailsJournal(
Journal *journal,
bool noHtmlMode, KDateTime::Spec spec )
1502 QString sSummary = i18n(
"Summary unspecified" );
1503 QString sDescr = i18n(
"Description unspecified" );
1504 if ( ! journal->
summary().isEmpty() ) {
1507 sSummary = cleanHtml( sSummary );
1513 sDescr = cleanHtml( sDescr );
1516 QString html(
"<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
1517 html += invitationRow( i18n(
"Summary:" ), sSummary );
1518 html += invitationRow( i18n(
"Date:" ),
dateToString( journal->
dtStart(),
false, spec ) );
1519 html += invitationRow( i18n(
"Description:" ), sDescr );
1520 html +=
"</table>\n";
1521 html += invitationsDetailsIncidence( journal, noHtmlMode );
1526 static QString invitationDetailsFreeBusy(
FreeBusy *fb,
bool noHtmlMode, KDateTime::Spec spec )
1528 Q_UNUSED( noHtmlMode );
1534 QString html(
"<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
1536 html += invitationRow( i18n(
"Start date:" ),
dateToString( fb->
dtStart(),
true, spec ) );
1537 html += invitationRow( i18n(
"End date:" ),
dateToString( fb->
dtEnd(),
true, spec ) );
1539 html +=
"<tr><td colspan=2><hr></td></tr>\n";
1540 html +=
"<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
1543 QList<Period>::iterator it;
1544 for ( it = periods.begin(); it != periods.end(); ++it ) {
1549 if ( dur >= 3600 ) {
1550 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600 );
1554 cont += i18ncp(
"minutes part of duration",
"1 minute",
"%1 minutes ", dur / 60 );
1558 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur );
1560 html += invitationRow(
1561 QString(), i18nc(
"startDate for duration",
"%1 for %2",
1562 KGlobal::locale()->formatDateTime(
1563 per.
start().dateTime(), KLocale::LongDate ), cont ) );
1566 if ( per.
start().date() == per.
end().date() ) {
1567 cont = i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1568 KGlobal::locale()->formatDate( per.
start().date() ),
1569 KGlobal::locale()->formatTime( per.
start().time() ),
1570 KGlobal::locale()->formatTime( per.
end().time() ) );
1572 cont = i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1573 KGlobal::locale()->formatDateTime(
1574 per.
start().dateTime(), KLocale::LongDate ),
1575 KGlobal::locale()->formatDateTime(
1576 per.
end().dateTime(), KLocale::LongDate ) );
1579 html += invitationRow( QString(), cont );
1583 html +=
"</table>\n";
1587 static bool replyMeansCounter(
Incidence * )
1606 static QString invitationHeaderEvent(
Event *event,
Incidence *existingIncidence,
1609 if ( !msg || !event ) {
1613 switch ( msg->
method() ) {
1615 return i18n(
"This invitation has been published" );
1617 if ( existingIncidence && event->
revision() > 0 ) {
1618 return i18n(
"This invitation has been updated by the organizer %1",
1621 if ( iamOrganizer( event ) ) {
1622 return i18n(
"I created this invitation" );
1624 if ( senderIsOrganizer( event, sender ) ) {
1626 return i18n(
"You received an invitation from %1",
1629 return i18n(
"You received an invitation" );
1633 return i18n(
"You received an invitation from %1 as a representative of %2",
1636 return i18n(
"You received an invitation from %1 as the organizer's representative",
1642 return i18n(
"This invitation was refreshed" );
1644 return i18n(
"This invitation has been canceled" );
1646 return i18n(
"Addition to the invitation" );
1649 if ( replyMeansCounter( event ) ) {
1650 return i18n(
"%1 makes this counter proposal",
1651 firstAttendeeName( event, i18n(
"Sender" ) ) );
1655 if( attendees.count() == 0 ) {
1656 kDebug() <<
"No attendees in the iCal reply!";
1659 if ( attendees.count() != 1 ) {
1660 kDebug() <<
"Warning: attendeecount in the reply should be 1"
1661 <<
"but is" << attendees.count();
1663 QString attendeeName = firstAttendeeName( event, i18n(
"Sender" ) );
1665 QString delegatorName, dummy;
1666 Attendee *attendee = *attendees.begin();
1667 KPIMUtils::extractEmailAddressAndName( attendee->
delegator(), dummy, delegatorName );
1668 if ( delegatorName.isEmpty() ) {
1672 switch( attendee->
status() ) {
1674 return i18n(
"%1 indicates this invitation still needs some action", attendeeName );
1677 if ( !sender.isEmpty() ) {
1678 return i18n(
"This invitation has been updated by attendee %1", sender );
1680 return i18n(
"This invitation has been updated by an attendee" );
1683 if ( delegatorName.isEmpty() ) {
1684 return i18n(
"%1 accepts this invitation", attendeeName );
1686 return i18n(
"%1 accepts this invitation on behalf of %2",
1687 attendeeName, delegatorName );
1691 if ( delegatorName.isEmpty() ) {
1692 return i18n(
"%1 tentatively accepts this invitation", attendeeName );
1694 return i18n(
"%1 tentatively accepts this invitation on behalf of %2",
1695 attendeeName, delegatorName );
1698 if ( delegatorName.isEmpty() ) {
1699 return i18n(
"%1 declines this invitation", attendeeName );
1701 return i18n(
"%1 declines this invitation on behalf of %2",
1702 attendeeName, delegatorName );
1706 QString delegate, dummy;
1707 KPIMUtils::extractEmailAddressAndName( attendee->
delegate(), dummy, delegate );
1708 if ( delegate.isEmpty() ) {
1711 if ( !delegate.isEmpty() ) {
1712 return i18n(
"%1 has delegated this invitation to %2", attendeeName, delegate );
1714 return i18n(
"%1 has delegated this invitation", attendeeName );
1718 return i18n(
"This invitation is now completed" );
1720 return i18n(
"%1 is still processing the invitation", attendeeName );
1721 case Attendee::None:
1722 return i18n(
"Unknown response to this invitation" );
1727 return i18n(
"%1 makes this counter proposal",
1728 firstAttendeeName( event, i18n(
"Sender" ) ) );
1730 case iTIPDeclineCounter:
1731 return i18n(
"%1 declines the counter proposal",
1732 firstAttendeeName( event, i18n(
"Sender" ) ) );
1735 return i18n(
"Error: Event iTIP message with unknown method" );
1737 kError() <<
"encountered an iTIP method that we do not support";
1741 static QString invitationHeaderTodo(
Todo *todo,
Incidence *existingIncidence,
1744 if ( !msg || !todo ) {
1748 switch ( msg->
method() ) {
1750 return i18n(
"This to-do has been published" );
1752 if ( existingIncidence && todo->
revision() > 0 ) {
1753 return i18n(
"This to-do has been updated by the organizer %1",
1756 if ( iamOrganizer( todo ) ) {
1757 return i18n(
"I created this to-do" );
1759 if ( senderIsOrganizer( todo, sender ) ) {
1761 return i18n(
"You have been assigned this to-do by %1", todo->
organizer().
fullName() );
1763 return i18n(
"You have been assigned this to-do" );
1767 return i18n(
"You have been assigned this to-do by %1 as a representative of %2",
1770 return i18n(
"You have been assigned this to-do by %1 as the "
1771 "organizer's representative", sender );
1777 return i18n(
"This to-do was refreshed" );
1779 return i18n(
"This to-do was canceled" );
1781 return i18n(
"Addition to the to-do" );
1784 if ( replyMeansCounter( todo ) ) {
1785 return i18n(
"%1 makes this counter proposal",
1786 firstAttendeeName( todo, i18n(
"Sender" ) ) );
1790 if ( attendees.count() == 0 ) {
1791 kDebug() <<
"No attendees in the iCal reply!";
1794 if ( attendees.count() != 1 ) {
1795 kDebug() <<
"Warning: attendeecount in the reply should be 1"
1796 <<
"but is" << attendees.count();
1798 QString attendeeName = firstAttendeeName( todo, i18n(
"Sender" ) );
1800 QString delegatorName, dummy;
1801 Attendee *attendee = *attendees.begin();
1802 KPIMUtils::extractEmailAddressAndName( attendee->
delegate(), dummy, delegatorName );
1803 if ( delegatorName.isEmpty() ) {
1807 switch( attendee->
status() ) {
1809 return i18n(
"%1 indicates this to-do assignment still needs some action",
1813 if ( !sender.isEmpty() ) {
1815 return i18n(
"This to-do has been completed by assignee %1", sender );
1817 return i18n(
"This to-do has been updated by assignee %1", sender );
1821 return i18n(
"This to-do has been completed by an assignee" );
1823 return i18n(
"This to-do has been updated by an assignee" );
1827 if ( delegatorName.isEmpty() ) {
1828 return i18n(
"%1 accepts this to-do", attendeeName );
1830 return i18n(
"%1 accepts this to-do on behalf of %2",
1831 attendeeName, delegatorName );
1835 if ( delegatorName.isEmpty() ) {
1836 return i18n(
"%1 tentatively accepts this to-do", attendeeName );
1838 return i18n(
"%1 tentatively accepts this to-do on behalf of %2",
1839 attendeeName, delegatorName );
1842 if ( delegatorName.isEmpty() ) {
1843 return i18n(
"%1 declines this to-do", attendeeName );
1845 return i18n(
"%1 declines this to-do on behalf of %2",
1846 attendeeName, delegatorName );
1850 QString delegate, dummy;
1851 KPIMUtils::extractEmailAddressAndName( attendee->
delegate(), dummy, delegate );
1852 if ( delegate.isEmpty() ) {
1855 if ( !delegate.isEmpty() ) {
1856 return i18n(
"%1 has delegated this to-do to %2", attendeeName, delegate );
1858 return i18n(
"%1 has delegated this to-do", attendeeName );
1862 return i18n(
"The request for this to-do is now completed" );
1864 return i18n(
"%1 is still processing the to-do", attendeeName );
1865 case Attendee::None:
1866 return i18n(
"Unknown response to this to-do" );
1871 return i18n(
"%1 makes this counter proposal",
1872 firstAttendeeName( todo, i18n(
"Sender" ) ) );
1874 case iTIPDeclineCounter:
1875 return i18n(
"%1 declines the counter proposal",
1876 firstAttendeeName( todo, i18n(
"Sender" ) ) );
1879 return i18n(
"Error: To-do iTIP message with unknown method" );
1881 kError() <<
"encountered an iTIP method that we do not support";
1887 if ( !msg || !journal ) {
1891 switch ( msg->
method() ) {
1893 return i18n(
"This journal has been published" );
1895 return i18n(
"You have been assigned this journal" );
1897 return i18n(
"This journal was refreshed" );
1899 return i18n(
"This journal was canceled" );
1901 return i18n(
"Addition to the journal" );
1904 if ( replyMeansCounter( journal ) ) {
1905 return i18n(
"Sender makes this counter proposal" );
1909 if ( attendees.count() == 0 ) {
1910 kDebug() <<
"No attendees in the iCal reply!";
1913 if( attendees.count() != 1 ) {
1914 kDebug() <<
"Warning: attendeecount in the reply should be 1 "
1915 <<
"but is " << attendees.count();
1917 Attendee *attendee = *attendees.begin();
1919 switch( attendee->
status() ) {
1921 return i18n(
"Sender indicates this journal assignment still needs some action" );
1923 return i18n(
"Sender accepts this journal" );
1925 return i18n(
"Sender tentatively accepts this journal" );
1927 return i18n(
"Sender declines this journal" );
1929 return i18n(
"Sender has delegated this request for the journal" );
1931 return i18n(
"The request for this journal is now completed" );
1933 return i18n(
"Sender is still processing the invitation" );
1934 case Attendee::None:
1935 return i18n(
"Unknown response to this journal" );
1940 return i18n(
"Sender makes this counter proposal" );
1941 case iTIPDeclineCounter:
1942 return i18n(
"Sender declines the counter proposal" );
1944 return i18n(
"Error: Journal iTIP message with unknown method" );
1946 kError() <<
"encountered an iTIP method that we do not support";
1952 if ( !msg || !fb ) {
1956 switch ( msg->
method() ) {
1958 return i18n(
"This free/busy list has been published" );
1960 return i18n(
"The free/busy list has been requested" );
1962 return i18n(
"This free/busy list was refreshed" );
1964 return i18n(
"This free/busy list was canceled" );
1966 return i18n(
"Addition to the free/busy list" );
1968 return i18n(
"Reply to the free/busy list" );
1970 return i18n(
"Sender makes this counter proposal" );
1971 case iTIPDeclineCounter:
1972 return i18n(
"Sender declines the counter proposal" );
1974 return i18n(
"Error: Free/Busy iTIP message with unknown method" );
1976 kError() <<
"encountered an iTIP method that we do not support";
1981 static QString invitationAttendees(
Incidence *incidence )
1988 tmpStr += i18n(
"Invitation List" );
1992 if ( !attendees.isEmpty() ) {
1994 Attendee::List::ConstIterator it;
1995 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
1997 if ( !iamAttendee( a ) ) {
2000 tmpStr +=
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">";
2004 tmpStr += invitationPerson( a->
email(), a->
name(), QString() );
2006 tmpStr += i18n(
" (delegated by %1)", a->
delegator() );
2009 tmpStr += i18n(
" (delegated to %1)", a->
delegate() );
2012 tmpStr +=
"<td>" + a->
statusStr() +
"</td>";
2018 tmpStr +=
"</table>";
2020 tmpStr +=
"<i> " + i18nc(
"no attendees",
"None" ) +
"</i>";
2026 static QString invitationAttachments( InvitationFormatterHelper *helper,
Incidence *incidence )
2034 if ( !attachments.isEmpty() ) {
2035 tmpStr += i18n(
"Attached Documents:" ) +
"<ol>";
2037 Attachment::List::ConstIterator it;
2038 for ( it = attachments.constBegin(); it != attachments.constEnd(); ++it ) {
2043 const QString iconStr = ( mimeType ?
2044 mimeType->iconName( a->
uri() ) :
2045 QString(
"application-octet-stream" ) );
2046 const QString iconPath = KIconLoader::global()->iconPath( iconStr, KIconLoader::Small );
2047 if ( !iconPath.isEmpty() ) {
2048 tmpStr +=
"<img valign=\"top\" src=\"" + iconPath +
"\">";
2050 tmpStr += helper->makeLink(
"ATTACH:" + a->
label(), a->
label() );
2060 class KCal::IncidenceFormatter::ScheduleMessageVisitor
2064 ScheduleMessageVisitor() : mExistingIncidence( 0 ), mMessage( 0 ) { mResult =
""; }
2068 mExistingIncidence = existingIncidence;
2071 return incidence->
accept( *
this );
2073 QString result()
const {
return mResult; }
2082 class KCal::IncidenceFormatter::InvitationHeaderVisitor :
2083 public IncidenceFormatter::ScheduleMessageVisitor
2086 bool visit(
Event *event )
2088 mResult = invitationHeaderEvent( event, mExistingIncidence, mMessage, mSender );
2089 return !mResult.isEmpty();
2091 bool visit(
Todo *todo )
2093 mResult = invitationHeaderTodo( todo, mExistingIncidence, mMessage, mSender );
2094 return !mResult.isEmpty();
2096 bool visit(
Journal *journal )
2098 mResult = invitationHeaderJournal( journal, mMessage );
2099 return !mResult.isEmpty();
2103 mResult = invitationHeaderFreeBusy( fb, mMessage );
2104 return !mResult.isEmpty();
2108 class KCal::IncidenceFormatter::InvitationBodyVisitor
2109 :
public IncidenceFormatter::ScheduleMessageVisitor
2112 InvitationBodyVisitor(
bool noHtmlMode, KDateTime::Spec spec )
2113 : ScheduleMessageVisitor(), mNoHtmlMode( noHtmlMode ), mSpec( spec ) {}
2116 bool visit(
Event *event )
2118 mResult = invitationDetailsEvent( event, mNoHtmlMode, mSpec );
2119 return !mResult.isEmpty();
2121 bool visit(
Todo *todo )
2123 mResult = invitationDetailsTodo( todo, mNoHtmlMode, mSpec );
2124 return !mResult.isEmpty();
2126 bool visit(
Journal *journal )
2128 mResult = invitationDetailsJournal( journal, mNoHtmlMode, mSpec );
2129 return !mResult.isEmpty();
2133 mResult = invitationDetailsFreeBusy( fb, mNoHtmlMode, mSpec );
2134 return !mResult.isEmpty();
2139 KDateTime::Spec mSpec;
2143 QString InvitationFormatterHelper::generateLinkURL(
const QString &
id )
2149 class IncidenceFormatter::IncidenceCompareVisitor
2153 IncidenceCompareVisitor() : mExistingIncidence( 0 ) {}
2156 if ( !existingIncidence ) {
2160 if ( !inc || !existingIncidence || inc->
revision() <= existingIncidence->
revision() ) {
2163 mExistingIncidence = existingIncidence;
2165 return incidence->
accept( *
this );
2168 QString result()
const
2170 if ( mChanges.isEmpty() ) {
2173 QString html =
"<div align=\"left\"><ul><li>";
2174 html += mChanges.join(
"</li><li>" );
2175 html +=
"</li><ul></div>";
2180 bool visit(
Event *event )
2182 compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
2183 compareIncidences( event, mExistingIncidence, mMethod );
2184 return !mChanges.isEmpty();
2186 bool visit(
Todo *todo )
2188 compareTodos( todo, dynamic_cast<Todo*>( mExistingIncidence ) );
2189 compareIncidences( todo, mExistingIncidence, mMethod );
2190 return !mChanges.isEmpty();
2192 bool visit(
Journal *journal )
2194 compareIncidences( journal, mExistingIncidence, mMethod );
2195 return !mChanges.isEmpty();
2200 return !mChanges.isEmpty();
2204 void compareEvents(
Event *newEvent,
Event *oldEvent )
2206 if ( !oldEvent || !newEvent ) {
2211 mChanges += i18n(
"The invitation starting time has been changed from %1 to %2",
2212 eventStartTimeStr( oldEvent ), eventStartTimeStr( newEvent ) );
2214 if ( oldEvent->
dtEnd() != newEvent->
dtEnd() ||
2216 mChanges += i18n(
"The invitation ending time has been changed from %1 to %2",
2217 eventEndTimeStr( oldEvent ), eventEndTimeStr( newEvent ) );
2221 void compareTodos(
Todo *newTodo,
Todo *oldTodo )
2223 if ( !oldTodo || !newTodo ) {
2228 mChanges += i18n(
"The to-do has been completed" );
2231 mChanges += i18n(
"The to-do is no longer completed" );
2236 mChanges += i18n(
"The task completed percentage has changed from %1 to %2",
2241 mChanges += i18n(
"A to-do starting time has been added" );
2244 mChanges += i18n(
"The to-do starting time has been removed" );
2248 mChanges += i18n(
"The to-do starting time has been changed from %1 to %2",
2254 mChanges += i18n(
"A to-do due time has been added" );
2257 mChanges += i18n(
"The to-do due time has been removed" );
2261 mChanges += i18n(
"The to-do due time has been changed from %1 to %2",
2269 if ( !oldInc || !newInc ) {
2274 mChanges += i18n(
"The summary has been changed to: \"%1\"",
2279 mChanges += i18nc(
"event/todo location",
"The location has been changed to: \"%1\"",
2284 mChanges += i18n(
"The description has been changed to: \"%1\"",
2290 for ( Attendee::List::ConstIterator it = newAttendees.constBegin();
2291 it != newAttendees.constEnd(); ++it ) {
2294 mChanges += i18n(
"Attendee %1 has been added", (*it)->fullName() );
2296 if ( oldAtt->
status() != (*it)->status() ) {
2297 mChanges += i18n(
"The status of attendee %1 has been changed to: %2",
2298 (*it)->fullName(), (*it)->statusStr() );
2303 if ( method == iTIPRequest ) {
2304 for ( Attendee::List::ConstIterator it = oldAttendees.constBegin();
2305 it != oldAttendees.constEnd(); ++it ) {
2309 mChanges += i18n(
"Attendee %1 has been removed", (*it)->fullName() );
2319 QStringList mChanges;
2323 QString InvitationFormatterHelper::makeLink(
const QString &
id,
const QString &text )
2325 if ( !
id.startsWith( QLatin1String(
"ATTACH:" ) ) ) {
2326 QString res = QString(
"<a href=\"%1\"><b>%2</b></a>" ).
2327 arg( generateLinkURL(
id ), text );
2331 QString res = QString(
"<a href=\"%1\">%2</a>" ).
2332 arg( generateLinkURL(
id ), text );
2341 #ifndef KDEPIM_NO_KRESOURCES
2343 if ( !cal || !incidence ) {
2351 if ( !subRes.contains(
"/.INBOX.directory/" ) ) {
2359 static QString tdOpen =
"<td style=\"border-width:2px;border-style:outset\">";
2360 static QString tdClose =
"</td>";
2362 static QString responseButtons(
Incidence *inc,
bool rsvpReq,
bool rsvpRec,
2363 InvitationFormatterHelper *helper )
2370 if ( !rsvpReq && ( inc && inc->
revision() == 0 ) ) {
2373 html += helper->makeLink(
"record", i18n(
"[Record]" ) );
2378 html += helper->makeLink(
"delete", i18n(
"[Move to Trash]" ) );
2385 html += helper->makeLink(
"accept", i18nc(
"accept invitation",
"Accept" ) );
2390 html += helper->makeLink(
"accept_conditionally",
2391 i18nc(
"Accept invitation conditionally",
"Accept cond." ) );
2396 html += helper->makeLink(
"counter",
2397 i18nc(
"invitation counter proposal",
"Counter proposal" ) );
2402 html += helper->makeLink(
"decline",
2403 i18nc(
"decline invitation",
"Decline" ) );
2407 if ( !rsvpRec || ( inc && inc->
revision() > 0 ) ) {
2410 html += helper->makeLink(
"delegate",
2411 i18nc(
"delegate inviation to another",
"Delegate" ) );
2416 html += helper->makeLink(
"forward",
2417 i18nc(
"forward request to another",
"Forward" ) );
2421 if ( inc && inc->
type() ==
"Event" ) {
2423 html += helper->makeLink(
"check_calendar",
2424 i18nc(
"look for scheduling conflicts",
"Check my calendar" ) );
2431 static QString counterButtons(
Incidence *incidence,
2432 InvitationFormatterHelper *helper )
2441 html += helper->makeLink(
"accept_counter", i18n(
"[Accept]" ) );
2446 html += helper->makeLink(
"decline_counter", i18n(
"[Decline]" ) );
2450 if ( incidence && incidence->
type() ==
"Event" ) {
2452 html += helper->makeLink(
"check_calendar", i18n(
"[Check my calendar] " ) );
2458 Calendar *InvitationFormatterHelper::calendar()
const
2463 static QString formatICalInvitationHelper( QString invitation,
2465 InvitationFormatterHelper *helper,
2467 KDateTime::Spec spec,
2468 const QString &sender )
2470 if ( invitation.isEmpty() ) {
2480 kDebug() <<
"Failed to parse the scheduling message";
2491 if ( incBase && helper->calendar() ) {
2492 existingIncidence = helper->calendar()->incidence( incBase->
uid() );
2493 if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) ) {
2494 existingIncidence = 0;
2496 if ( !existingIncidence ) {
2498 for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
2499 if ( (*it)->schedulingID() == incBase->
uid() &&
2500 incidenceOwnedByMe( helper->calendar(), *it ) ) {
2501 existingIncidence = *it;
2510 html +=
"<div align=\"center\" style=\"border:solid 1px;\">";
2512 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
2514 if ( !headerVisitor.act( incBase, existingIncidence, msg, sender ) ) {
2517 html += htmlAddTag(
"h3", headerVisitor.result() );
2519 IncidenceFormatter::InvitationBodyVisitor bodyVisitor( noHtmlMode, spec );
2520 if ( !bodyVisitor.act( incBase, existingIncidence, msg, sender ) ) {
2523 html += bodyVisitor.result();
2525 if ( msg->
method() == iTIPRequest ) {
2526 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
2527 if ( compareVisitor.act( incBase, existingIncidence, msg->
method() ) ) {
2528 html +=
"<p align=\"left\">";
2529 html += i18n(
"The following changes have been made by the organizer:" );
2531 html += compareVisitor.result();
2534 if ( msg->
method() == iTIPReply ) {
2535 IncidenceCompareVisitor compareVisitor;
2536 if ( compareVisitor.act( incBase, existingIncidence, msg->
method() ) ) {
2537 html +=
"<p align=\"left\">";
2538 if ( !sender.isEmpty() ) {
2539 html += i18n(
"The following changes have been made by %1:", sender );
2541 html += i18n(
"The following changes have been made by an attendee:" );
2544 html += compareVisitor.result();
2551 bool myInc = iamOrganizer( inc );
2554 bool rsvpRec =
false;
2557 Incidence *rsvpIncidence = existingIncidence;
2558 if ( !rsvpIncidence && inc && inc->
revision() > 0 ) {
2559 rsvpIncidence = inc;
2561 if ( rsvpIncidence ) {
2562 ea = findMyAttendee( rsvpIncidence );
2574 bool isDelegated =
false;
2575 Attendee *a = findMyAttendee( inc );
2587 bool rsvpReq = rsvpRequested( inc );
2588 if ( !myInc && a ) {
2591 if ( rsvpRec && inc ) {
2593 html += i18n(
"Your <b>%1</b> response has already been recorded", ea->
statusStr() );
2595 html += i18n(
"Your status for this invitation is <b>%1</b>", ea->
statusStr() );
2598 }
else if ( msg->
method() == iTIPCancel ) {
2599 html += i18n(
"This invitation was declined" );
2600 }
else if ( msg->
method() == iTIPAdd ) {
2601 html += i18n(
"This invitation was accepted" );
2603 if ( !isDelegated ) {
2604 html += rsvpRequestedStr( rsvpReq, role );
2606 html += i18n(
"Awaiting delegation response" );
2614 if ( inc && inc->
revision() == 0 ) {
2615 QString statStr = myStatusStr( inc );
2616 if ( !statStr.isEmpty() ) {
2628 html +=
"<table border=\"0\" align=\"center\" cellspacing=\"4\"><tr>";
2630 switch ( msg->
method() ) {
2636 if ( inc && inc->
revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
2637 if ( inc->
type() ==
"Todo" ) {
2638 html += helper->makeLink(
"reply", i18n(
"[Record invitation in my to-do list]" ) );
2640 html += helper->makeLink(
"reply", i18n(
"[Record invitation in my calendar]" ) );
2644 if ( !myInc && a ) {
2645 html += responseButtons( inc, rsvpReq, rsvpRec, helper );
2654 if ( inc->
type() ==
"Todo" ) {
2655 html += helper->makeLink(
"cancel",
2656 i18n(
"Remove invitation from my to-do list" ) );
2658 html += helper->makeLink(
"cancel",
2659 i18n(
"Remove invitation from my calendar" ) );
2672 if ( replyMeansCounter( inc ) ) {
2673 html +=
"<tr>" + counterButtons( inc, helper ) +
"</tr>";
2682 a = findDelegatedFromMyAttendee( inc );
2686 html += responseButtons( inc, rsvpReq, rsvpRec, helper );
2695 if ( a && helper->calendar() ) {
2696 ea = findAttendee( existingIncidence, a->
email() );
2701 html += htmlAddTag(
"i", i18n(
"The response has already been recorded" ) );
2705 if ( inc->
type() ==
"Todo" ) {
2706 html += helper->makeLink(
"reply", i18n(
"[Record response in my to-do list]" ) );
2708 html += helper->makeLink(
"reply", i18n(
"[Record response in my calendar]" ) );
2717 html += counterButtons( inc, helper );
2720 case iTIPDeclineCounter:
2726 html +=
"</tr></table>";
2729 if ( myInc && helper->calendar() ) {
2730 html += invitationAttendees( helper->calendar()->incidence( inc->
uid() ) );
2737 html += invitationAttachments( helper, inc );
2745 InvitationFormatterHelper *helper )
2747 return formatICalInvitationHelper( invitation, calendar, helper,
false,
2748 KSystemTimeZones::local(), QString() );
2753 InvitationFormatterHelper *helper )
2755 return formatICalInvitationHelper( invitation, calendar, helper,
true,
2756 KSystemTimeZones::local(), QString() );
2761 InvitationFormatterHelper *helper,
2762 const QString &sender )
2764 return formatICalInvitationHelper( invitation, calendar, helper,
true,
2765 KSystemTimeZones::local(), sender );
2773 class KCal::IncidenceFormatter::ToolTipVisitor
2778 : mRichText( true ), mSpec( KDateTime::Spec() ), mResult(
"" ) {}
2781 const QDate &date=QDate(),
bool richText=
true,
2782 KDateTime::Spec spec=KDateTime::Spec() )
2784 mCalendar = calendar;
2787 mRichText = richText;
2790 return incidence ? incidence->
accept( *
this ) :
false;
2793 bool act(
const QString &location,
IncidenceBase *incidence,
2794 const QDate &date=QDate(),
bool richText=
true,
2795 KDateTime::Spec spec=KDateTime::Spec() )
2798 mLocation = location;
2800 mRichText = richText;
2803 return incidence ? incidence->
accept( *
this ) :
false;
2806 QString result()
const {
return mResult; }
2814 QString dateRangeText(
Event *event,
const QDate &date );
2815 QString dateRangeText(
Todo *todo,
const QDate &date );
2816 QString dateRangeText(
Journal *journal );
2817 QString dateRangeText(
FreeBusy *fb );
2819 QString generateToolTip(
Incidence *incidence, QString dtRangeText );
2826 KDateTime::Spec mSpec;
2830 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
Event *event,
const QDate &date )
2836 KDateTime startDt =
event->dtStart();
2837 KDateTime endDt =
event->dtEnd();
2839 if ( date.isValid() ) {
2840 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
2841 int diffDays = startDt.daysTo( kdt );
2842 kdt = kdt.addSecs( -1 );
2845 endDt = endDt.addDays( diffDays );
2846 if ( startDt > endDt ) {
2848 endDt = startDt.addDays( event->
dtStart().daysTo( event->
dtEnd() ) );
2856 ret +=
"<br>" + i18nc(
"Event start",
"<i>From:</i> %1", tmp );
2859 ret +=
"<br>" + i18nc(
"Event end",
"<i>To:</i> %1", tmp );
2864 i18n(
"<i>Date:</i> %1",
dateToString( startDt,
false, mSpec ) );
2865 if ( !event->
allDay() ) {
2866 const QString dtStartTime =
timeToString( startDt,
true, mSpec );
2867 const QString dtEndTime =
timeToString( endDt,
true, mSpec );
2868 if ( dtStartTime == dtEndTime ) {
2871 i18nc(
"time for event",
"<i>Time:</i> %1",
2875 i18nc(
"time range for event",
2876 "<i>Time:</i> %1 - %2",
2877 dtStartTime, dtEndTime );
2882 return ret.replace(
' ',
" " );
2885 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
Todo *todo,
const QDate &date )
2890 KDateTime startDt = todo->
dtStart();
2892 if ( date.isValid() ) {
2893 startDt.setDate( date );
2897 i18n(
"<i>Start:</i> %1",
dateToString( startDt,
false, mSpec ) );
2901 KDateTime dueDt = todo->
dtDue();
2903 if ( date.isValid() ) {
2904 KDateTime kdt( date, QTime( 0, 0, 0 ), KSystemTimeZones::local() );
2905 kdt = kdt.addSecs( -1 );
2910 i18n(
"<i>Due:</i> %1",
2918 ret +=
"<i>" + i18n(
"Priority:" ) +
"</i>" +
" ";
2919 ret += QString::number( todo->
priority() );
2924 ret +=
"<i>" + i18nc(
"Completed: date",
"Completed:" ) +
"</i>" +
" ";
2927 ret +=
"<i>" + i18n(
"Percent Done:" ) +
"</i>" +
" ";
2931 return ret.replace(
' ',
" " );
2934 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
Journal *journal )
2938 if ( journal->
dtStart().isValid() ) {
2942 return ret.replace(
' ',
" " );
2945 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
FreeBusy *fb )
2950 i18n(
"<i>Period start:</i> %1",
2951 KGlobal::locale()->formatDateTime( fb->
dtStart().dateTime() ) );
2953 i18n(
"<i>Period start:</i> %1",
2954 KGlobal::locale()->formatDateTime( fb->
dtEnd().dateTime() ) );
2955 return ret.replace(
' ',
" " );
2958 bool IncidenceFormatter::ToolTipVisitor::visit(
Event *event )
2960 mResult = generateToolTip( event, dateRangeText( event, mDate ) );
2961 return !mResult.isEmpty();
2964 bool IncidenceFormatter::ToolTipVisitor::visit(
Todo *todo )
2966 mResult = generateToolTip( todo, dateRangeText( todo, mDate ) );
2967 return !mResult.isEmpty();
2970 bool IncidenceFormatter::ToolTipVisitor::visit(
Journal *journal )
2972 mResult = generateToolTip( journal, dateRangeText( journal ) );
2973 return !mResult.isEmpty();
2976 bool IncidenceFormatter::ToolTipVisitor::visit(
FreeBusy *fb )
2979 mResult =
"<qt><b>" + i18n(
"Free/Busy information for %1", fb->
organizer().
fullName() ) +
"</b>";
2980 mResult += dateRangeText( fb );
2982 return !mResult.isEmpty();
2985 static QString tooltipPerson(
const QString &email, QString name )
2989 if ( name.isEmpty() && !email.isEmpty() ) {
2990 #ifndef KDEPIM_NO_KRESOURCES
2991 KABC::AddressBook *add_book = KABC::StdAddressBook::self(
true );
2992 KABC::Addressee::List addressList = add_book->findByEmail( email );
2993 if ( !addressList.isEmpty() ) {
2994 KABC::Addressee o = addressList.first();
2995 if ( !o.isEmpty() && addressList.size() < 2 ) {
2997 name = o.formattedName();
3004 QString tmpString = ( name.isEmpty() ? email : name );
3012 QString sep = i18nc(
"separator for lists of people names",
", " );
3013 int sepLen = sep.length();
3017 Attendee::List::ConstIterator it;
3020 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
3022 if ( a->
role() != role ) {
3030 if ( i == maxNumAtts ) {
3031 static QString etc = i18nc(
"elipsis",
"..." );
3035 tmpStr += tooltipPerson( a->
email(), a->
name() );
3037 tmpStr += i18n(
" (delegated by %1)", a->
delegator() );
3040 tmpStr += i18n(
" (delegated to %1)", a->
delegate() );
3045 if ( tmpStr.endsWith( sep ) ) {
3046 tmpStr.truncate( tmpStr.length() - sepLen );
3051 static QString tooltipFormatAttendees(
Incidence *incidence )
3053 QString tmpStr, str;
3056 int attendeeCount = incidence->
attendees().count();
3057 if ( attendeeCount > 1 ||
3058 ( attendeeCount == 1 &&
3060 tmpStr +=
"<i>" + i18n(
"Organizer:" ) +
"</i>" +
" ";
3067 if ( !str.isEmpty() ) {
3068 tmpStr +=
"<br><i>" + i18n(
"Chair:" ) +
"</i>" +
" ";
3074 if ( !str.isEmpty() ) {
3075 tmpStr +=
"<br><i>" + i18n(
"Required Participants:" ) +
"</i>" +
" ";
3081 if ( !str.isEmpty() ) {
3082 tmpStr +=
"<br><i>" + i18n(
"Optional Participants:" ) +
"</i>" +
" ";
3088 if ( !str.isEmpty() ) {
3089 tmpStr +=
"<br><i>" + i18n(
"Observers:" ) +
"</i>" +
" ";
3096 QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
Incidence *incidence,
3097 QString dtRangeText )
3099 int maxDescLen = 120;
3106 QString tmp =
"<qt>";
3112 QString calStr = mLocation;
3116 if ( !calStr.isEmpty() ) {
3117 tmp +=
"<i>" + i18n(
"Calendar:" ) +
"</i>" +
" ";
3123 if ( !incidence->
location().isEmpty() ) {
3125 tmp +=
"<i>" + i18nc(
"event/todo location",
"Location:" ) +
"</i>" +
" ";
3130 if ( !durStr.isEmpty() ) {
3132 tmp +=
"<i>" + i18n(
"Duration:" ) +
"</i>" +
" ";
3136 if ( incidence->
recurs() ) {
3138 tmp +=
"<i>" + i18n(
"Recurrence:" ) +
"</i>" +
" ";
3145 if ( desc.length() > maxDescLen ) {
3146 static QString etc = i18nc(
"elipsis",
"..." );
3147 desc = desc.left( maxDescLen ) + etc;
3149 desc = Qt::escape( desc ).replace(
'\n',
"<br>" );
3154 tmp +=
"<i>" + i18n(
"Description:" ) +
"</i>" +
"<br>";
3159 int reminderCount = incidence->
alarms().count();
3162 tmp +=
"<i>" + i18np(
"Reminder:",
"Reminders:", reminderCount ) +
"</i>" +
" ";
3167 tmp += tooltipFormatAttendees( incidence );
3169 int categoryCount = incidence->
categories().count();
3170 if ( categoryCount > 0 ) {
3172 tmp +=
"<i>" + i18np(
"Category:",
"Categories:", categoryCount ) +
"</i>" +
" ";
3184 return toolTipStr( 0, incidence, QDate(), richText, KDateTime::Spec() );
3188 bool richText, KDateTime::Spec spec )
3191 if ( v.act( 0, incidence, QDate(), richText, spec ) ) {
3201 bool richText, KDateTime::Spec spec )
3204 if ( v.act( calendar, incidence, date, richText, spec ) ) {
3214 bool richText, KDateTime::Spec spec )
3217 if ( v.act( sourceName, incidence, date, richText, spec ) ) {
3229 static QString mailBodyIncidence(
Incidence *incidence )
3232 if ( !incidence->
summary().isEmpty() ) {
3233 body += i18n(
"Summary: %1\n", incidence->
richSummary() );
3238 if ( !incidence->
location().isEmpty() ) {
3239 body += i18nc(
"event/todo location",
"Location: %1\n", incidence->
richLocation() );
3246 class KCal::IncidenceFormatter::MailBodyVisitor
3251 : mSpec( KDateTime::Spec() ), mResult(
"" ) {}
3253 bool act(
IncidenceBase *incidence, KDateTime::Spec spec=KDateTime::Spec() )
3257 return incidence ? incidence->
accept( *
this ) :
false;
3259 QString result()
const
3270 mResult = i18n(
"This is a Free Busy Object" );
3271 return !mResult.isEmpty();
3274 KDateTime::Spec mSpec;
3278 bool IncidenceFormatter::MailBodyVisitor::visit(
Event *event )
3280 QString recurrence[]= {
3281 i18nc(
"no recurrence",
"None" ),
3282 i18nc(
"event recurs by minutes",
"Minutely" ),
3283 i18nc(
"event recurs by hours",
"Hourly" ),
3284 i18nc(
"event recurs by days",
"Daily" ),
3285 i18nc(
"event recurs by weeks",
"Weekly" ),
3286 i18nc(
"event recurs same position (e.g. first monday) each month",
"Monthly Same Position" ),
3287 i18nc(
"event recurs same day each month",
"Monthly Same Day" ),
3288 i18nc(
"event recurs same month each year",
"Yearly Same Month" ),
3289 i18nc(
"event recurs same day each year",
"Yearly Same Day" ),
3290 i18nc(
"event recurs same position (e.g. first monday) each year",
"Yearly Same Position" )
3293 mResult = mailBodyIncidence( event );
3295 if ( !event->
allDay() ) {
3298 if ( event->
dtStart() !=
event->dtEnd() ) {
3299 mResult += i18n(
"End Date: %1\n",
dateToString( event->
dtEnd(),
true, mSpec ) );
3301 if ( !event->
allDay() ) {
3302 mResult += i18n(
"End Time: %1\n",
timeToString( event->
dtEnd(),
true, mSpec ) );
3307 mResult += i18n(
"Recurs: %1\n", recurrence[ recur->
recurrenceType() ] );
3311 mResult += i18np(
"Repeats once",
"Repeats %1 times", recur->
duration() );
3318 endstr = KGlobal::locale()->formatDate( recur->
endDate() );
3320 endstr = KGlobal::locale()->formatDateTime( recur->
endDateTime().dateTime() );
3322 mResult += i18n(
"Repeat until: %1\n", endstr );
3324 mResult += i18n(
"Repeats forever\n" );
3329 QString details =
event->richDescription();
3330 if ( !details.isEmpty() ) {
3331 mResult += i18n(
"Details:\n%1\n", details );
3333 return !mResult.isEmpty();
3336 bool IncidenceFormatter::MailBodyVisitor::visit(
Todo *todo )
3338 mResult = mailBodyIncidence( todo );
3341 mResult += i18n(
"Start Date: %1\n",
dateToString( todo->
dtStart(
false ),
true, mSpec ) );
3343 mResult += i18n(
"Start Time: %1\n",
timeToString( todo->
dtStart(
false ),
true, mSpec ) );
3347 mResult += i18n(
"Due Date: %1\n",
dateToString( todo->
dtDue(),
true, mSpec ) );
3349 mResult += i18n(
"Due Time: %1\n",
timeToString( todo->
dtDue(),
true, mSpec ) );
3353 if ( !details.isEmpty() ) {
3354 mResult += i18n(
"Details:\n%1\n", details );
3356 return !mResult.isEmpty();
3359 bool IncidenceFormatter::MailBodyVisitor::visit(
Journal *journal )
3361 mResult = mailBodyIncidence( journal );
3363 if ( !journal->
allDay() ) {
3367 mResult += i18n(
"Text of the journal:\n%1\n", journal->
richDescription() );
3369 return !mResult.isEmpty();
3375 return mailBodyStr( incidence, KDateTime::Spec() );
3379 KDateTime::Spec spec )
3386 if ( v.act( incidence, spec ) ) {
3393 static QString recurEnd(
Incidence *incidence )
3396 if ( incidence->
allDay() ) {
3411 if ( !incidence->
recurs() ) {
3412 return i18n(
"No recurrence" );
3414 QStringList dayList;
3415 dayList.append( i18n(
"31st Last" ) );
3416 dayList.append( i18n(
"30th Last" ) );
3417 dayList.append( i18n(
"29th Last" ) );
3418 dayList.append( i18n(
"28th Last" ) );
3419 dayList.append( i18n(
"27th Last" ) );
3420 dayList.append( i18n(
"26th Last" ) );
3421 dayList.append( i18n(
"25th Last" ) );
3422 dayList.append( i18n(
"24th Last" ) );
3423 dayList.append( i18n(
"23rd Last" ) );
3424 dayList.append( i18n(
"22nd Last" ) );
3425 dayList.append( i18n(
"21st Last" ) );
3426 dayList.append( i18n(
"20th Last" ) );
3427 dayList.append( i18n(
"19th Last" ) );
3428 dayList.append( i18n(
"18th Last" ) );
3429 dayList.append( i18n(
"17th Last" ) );
3430 dayList.append( i18n(
"16th Last" ) );
3431 dayList.append( i18n(
"15th Last" ) );
3432 dayList.append( i18n(
"14th Last" ) );
3433 dayList.append( i18n(
"13th Last" ) );
3434 dayList.append( i18n(
"12th Last" ) );
3435 dayList.append( i18n(
"11th Last" ) );
3436 dayList.append( i18n(
"10th Last" ) );
3437 dayList.append( i18n(
"9th Last" ) );
3438 dayList.append( i18n(
"8th Last" ) );
3439 dayList.append( i18n(
"7th Last" ) );
3440 dayList.append( i18n(
"6th Last" ) );
3441 dayList.append( i18n(
"5th Last" ) );
3442 dayList.append( i18n(
"4th Last" ) );
3443 dayList.append( i18n(
"3rd Last" ) );
3444 dayList.append( i18n(
"2nd Last" ) );
3445 dayList.append( i18nc(
"last day of the month",
"Last" ) );
3446 dayList.append( i18nc(
"unknown day of the month",
"unknown" ) );
3447 dayList.append( i18n(
"1st" ) );
3448 dayList.append( i18n(
"2nd" ) );
3449 dayList.append( i18n(
"3rd" ) );
3450 dayList.append( i18n(
"4th" ) );
3451 dayList.append( i18n(
"5th" ) );
3452 dayList.append( i18n(
"6th" ) );
3453 dayList.append( i18n(
"7th" ) );
3454 dayList.append( i18n(
"8th" ) );
3455 dayList.append( i18n(
"9th" ) );
3456 dayList.append( i18n(
"10th" ) );
3457 dayList.append( i18n(
"11th" ) );
3458 dayList.append( i18n(
"12th" ) );
3459 dayList.append( i18n(
"13th" ) );
3460 dayList.append( i18n(
"14th" ) );
3461 dayList.append( i18n(
"15th" ) );
3462 dayList.append( i18n(
"16th" ) );
3463 dayList.append( i18n(
"17th" ) );
3464 dayList.append( i18n(
"18th" ) );
3465 dayList.append( i18n(
"19th" ) );
3466 dayList.append( i18n(
"20th" ) );
3467 dayList.append( i18n(
"21st" ) );
3468 dayList.append( i18n(
"22nd" ) );
3469 dayList.append( i18n(
"23rd" ) );
3470 dayList.append( i18n(
"24th" ) );
3471 dayList.append( i18n(
"25th" ) );
3472 dayList.append( i18n(
"26th" ) );
3473 dayList.append( i18n(
"27th" ) );
3474 dayList.append( i18n(
"28th" ) );
3475 dayList.append( i18n(
"29th" ) );
3476 dayList.append( i18n(
"30th" ) );
3477 dayList.append( i18n(
"31st" ) );
3478 int weekStart = KGlobal::locale()->weekStartDay();
3481 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
3484 case Recurrence::rNone:
3485 return i18n(
"No recurrence" );
3486 case Recurrence::rMinutely:
3488 txt = i18np(
"Recurs every minute until %2",
3489 "Recurs every %1 minutes until %2",
3490 recur->
frequency(), recurEnd( incidence ) );
3492 txt += i18nc(
"number of occurrences",
3493 " (<numid>%1</numid> occurrences)",
3498 return i18np(
"Recurs every minute",
3499 "Recurs every %1 minutes", recur->
frequency() );
3500 case Recurrence::rHourly:
3502 txt = i18np(
"Recurs hourly until %2",
3503 "Recurs every %1 hours until %2",
3504 recur->
frequency(), recurEnd( incidence ) );
3506 txt += i18nc(
"number of occurrences",
3507 " (<numid>%1</numid> occurrences)",
3512 return i18np(
"Recurs hourly",
"Recurs every %1 hours", recur->
frequency() );
3513 case Recurrence::rDaily:
3515 txt = i18np(
"Recurs daily until %2",
3516 "Recurs every %1 days until %2",
3517 recur->
frequency(), recurEnd( incidence ) );
3519 txt += i18nc(
"number of occurrences",
3520 " (<numid>%1</numid> occurrences)",
3525 return i18np(
"Recurs daily",
"Recurs every %1 days", recur->
frequency() );
3526 case Recurrence::rWeekly:
3528 bool addSpace =
false;
3529 for (
int i = 0; i < 7; ++i ) {
3530 if ( recur->
days().testBit( ( i + weekStart + 6 ) % 7 ) ) {
3532 dayNames.append( i18nc(
"separator for list of days",
", " ) );
3534 dayNames.append( calSys->weekDayName( ( ( i + weekStart + 6 ) % 7 ) + 1,
3535 KCalendarSystem::ShortDayName ) );
3539 if ( dayNames.isEmpty() ) {
3540 dayNames = i18nc(
"Recurs weekly on no days",
"no days" );
3543 txt = i18ncp(
"Recurs weekly on [list of days] until end-date",
3544 "Recurs weekly on %2 until %3",
3545 "Recurs every <numid>%1</numid> weeks on %2 until %3",
3546 recur->
frequency(), dayNames, recurEnd( incidence ) );
3548 txt += i18nc(
"number of occurrences",
3549 " (<numid>%1</numid> occurrences)",
3554 return i18ncp(
"Recurs weekly on [list of days]",
3555 "Recurs weekly on %2",
3556 "Recurs every <numid>%1</numid> weeks on %2",
3559 case Recurrence::rMonthlyPos:
3564 txt = i18ncp(
"Recurs every N months on the [2nd|3rd|...]"
3565 " weekdayname until end-date",
3566 "Recurs every month on the %2 %3 until %4",
3567 "Recurs every <numid>%1</numid> months on the %2 %3 until %4",
3569 dayList[rule.pos() + 31],
3570 calSys->weekDayName( rule.day(), KCalendarSystem::LongDayName ),
3571 recurEnd( incidence ) );
3573 txt += i18nc(
"number of occurrences",
3574 " (<numid>%1</numid> occurrences)",
3579 return i18ncp(
"Recurs every N months on the [2nd|3rd|...] weekdayname",
3580 "Recurs every month on the %2 %3",
3581 "Recurs every %1 months on the %2 %3",
3583 dayList[rule.pos() + 31],
3584 calSys->weekDayName( rule.day(), KCalendarSystem::LongDayName ) );
3588 case Recurrence::rMonthlyDay:
3593 txt = i18ncp(
"Recurs monthly on the [1st|2nd|...] day until end-date",
3594 "Recurs monthly on the %2 day until %3",
3595 "Recurs every %1 months on the %2 day until %3",
3598 recurEnd( incidence ) );
3600 txt += i18nc(
"number of occurrences",
3601 " (<numid>%1</numid> occurrences)",
3606 return i18ncp(
"Recurs monthly on the [1st|2nd|...] day",
3607 "Recurs monthly on the %2 day",
3608 "Recurs every <numid>%1</numid> month on the %2 day",
3610 dayList[days + 31] );
3614 case Recurrence::rYearlyMonth:
3618 txt = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]"
3620 "Recurs yearly on %2 %3 until %4",
3621 "Recurs every %1 years on %2 %3 until %4",
3625 recurEnd( incidence ) );
3627 txt += i18nc(
"number of occurrences",
3628 " (<numid>%1</numid> occurrences)",
3635 return i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]",
3636 "Recurs yearly on %2 %3",
3637 "Recurs every %1 years on %2 %3",
3641 dayList[ recur->
yearDates()[0] + 31 ] );
3644 return i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
3645 "Recurs yearly on %1 %2",
3648 dayList[ recur->
startDate().day() + 31 ] );
3650 return i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
3651 "Recurs yearly on %1 %2",
3652 calSys->monthName( recur->
startDate().month(),
3654 dayList[ recur->
startDate().day() + 31 ] );
3659 case Recurrence::rYearlyDay:
3660 if ( !recur->
yearDays().isEmpty() ) {
3662 txt = i18ncp(
"Recurs every N years on day N until end-date",
3663 "Recurs every year on day <numid>%2</numid> until %3",
3664 "Recurs every <numid>%1</numid> years"
3665 " on day <numid>%2</numid> until %3",
3668 recurEnd( incidence ) );
3670 txt += i18nc(
"number of occurrences",
3671 " (<numid>%1</numid> occurrences)",
3676 return i18ncp(
"Recurs every N YEAR[S] on day N",
3677 "Recurs every year on day <numid>%2</numid>",
3678 "Recurs every <numid>%1</numid> years"
3679 " on day <numid>%2</numid>",
3683 case Recurrence::rYearlyPos:
3688 txt = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
3689 "of monthname until end-date",
3690 "Every year on the %2 %3 of %4 until %5",
3691 "Every <numid>%1</numid> years on the %2 %3 of %4"
3694 dayList[rule.pos() + 31],
3695 calSys->weekDayName( rule.day(), KCalendarSystem::LongDayName ),
3697 recurEnd( incidence ) );
3699 txt += i18nc(
"number of occurrences",
3700 " (<numid>%1</numid> occurrences)",
3705 return i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
3707 "Every year on the %2 %3 of %4",
3708 "Every <numid>%1</numid> years on the %2 %3 of %4",
3710 dayList[rule.pos() + 31],
3711 calSys->weekDayName( rule.day(), KCalendarSystem::LongDayName ),
3717 return i18n(
"Incidence recurs" );
3722 const KDateTime::Spec &spec )
3724 if ( spec.isValid() ) {
3727 if ( spec.timeZone() != KSystemTimeZones::local() ) {
3728 timeZone =
' ' + spec.timeZone().name();
3731 return KGlobal::locale()->formatTime( date.toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
3733 return KGlobal::locale()->formatTime( date.time(), !shortfmt );
3739 const KDateTime::Spec &spec )
3741 if ( spec.isValid() ) {
3744 if ( spec.timeZone() != KSystemTimeZones::local() ) {
3745 timeZone =
' ' + spec.timeZone().name();
3749 KGlobal::locale()->formatDate( date.toTimeSpec( spec ).date(),
3750 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) +
3754 KGlobal::locale()->formatDate( date.date(),
3755 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
3762 const KDateTime::Spec &spec )
3768 if ( spec.isValid() ) {
3770 if ( spec.timeZone() != KSystemTimeZones::local() ) {
3771 timeZone =
' ' + spec.timeZone().name();
3774 return KGlobal::locale()->formatDateTime(
3775 date.toTimeSpec( spec ).dateTime(),
3776 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
3778 return KGlobal::locale()->formatDateTime(
3780 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
3786 #ifndef KDEPIM_NO_KRESOURCES
3787 if ( !calendar || !incidence ) {
3792 if ( !calendarResource ) {
3797 if ( resourceCalendar ) {
3800 if ( subRes.isEmpty() ) {
3812 static QString secs2Duration(
int secs )
3815 int days = secs / 86400;
3817 tmp += i18np(
"1 day",
"%1 days", days );
3819 secs -= ( days * 86400 );
3821 int hours = secs / 3600;
3823 tmp += i18np(
"1 hour",
"%1 hours", hours );
3825 secs -= ( hours * 3600 );
3827 int mins = secs / 60;
3829 tmp += i18np(
"1 minute",
"%1 minutes", mins );
3837 if ( incidence->
type() ==
"Event" ) {
3838 Event *
event =
static_cast<Event *
>( incidence );
3840 if ( !event->
allDay() ) {
3841 tmp = secs2Duration( event->
dtStart().secsTo( event->
dtEnd() ) );
3843 tmp = i18np(
"1 day",
"%1 days",
3844 event->
dtStart().date().daysTo( event->
dtEnd().date() ) + 1 );
3847 tmp = i18n(
"forever" );
3849 }
else if ( incidence->
type() ==
"Todo" ) {
3850 Todo *todo =
static_cast<Todo *
>( incidence );
3854 tmp = secs2Duration( todo->
dtStart().secsTo( todo->
dtDue() ) );
3856 tmp = i18np(
"1 day",
"%1 days",
3857 todo->
dtStart().date().daysTo( todo->
dtDue().date() ) + 1 );
3868 Q_UNUSED( shortfmt );
3874 Alarm::List::ConstIterator it;
3875 for ( it = alarms.constBegin(); it != alarms.constEnd(); ++it ) {
3878 QString remStr, atStr, offsetStr;
3881 if ( alarm->
time().isValid() ) {
3882 atStr = KGlobal::locale()->formatDateTime( alarm->
time() );
3888 offsetStr = i18nc(
"N days/hours/minutes before the start datetime",
3889 "%1 before the start", secs2Duration( offset ) );
3890 }
else if ( offset > 0 ) {
3891 offsetStr = i18nc(
"N days/hours/minutes after the start datetime",
3892 "%1 after the start", secs2Duration( offset ) );
3894 if ( incidence->
dtStart().isValid() ) {
3895 atStr = KGlobal::locale()->formatDateTime( incidence->
dtStart() );
3902 if ( incidence->
type() ==
"Todo" ) {
3903 offsetStr = i18nc(
"N days/hours/minutes before the due datetime",
3904 "%1 before the to-do is due", secs2Duration( offset ) );
3906 offsetStr = i18nc(
"N days/hours/minutes before the end datetime",
3907 "%1 before the end", secs2Duration( offset ) );
3909 }
else if ( offset > 0 ) {
3910 if ( incidence->
type() ==
"Todo" ) {
3911 offsetStr = i18nc(
"N days/hours/minutes after the due datetime",
3912 "%1 after the to-do is due", secs2Duration( offset ) );
3914 offsetStr = i18nc(
"N days/hours/minutes after the end datetime",
3915 "%1 after the end", secs2Duration( offset ) );
3918 if ( incidence->
type() ==
"Todo" ) {
3919 Todo *t =
static_cast<Todo *
>( incidence );
3920 if ( t->
dtDue().isValid() ) {
3921 atStr = KGlobal::locale()->formatDateTime( t->
dtDue() );
3924 Event *e =
static_cast<Event *
>( incidence );
3925 if ( e->
dtEnd().isValid() ) {
3926 atStr = KGlobal::locale()->formatDateTime( e->
dtEnd() );
3931 if ( offset == 0 ) {
3932 if ( !atStr.isEmpty() ) {
3933 remStr = i18nc(
"reminder occurs at datetime",
"at %1", atStr );
3940 QString countStr = i18np(
"repeats once",
"repeats %1 times", alarm->
repeatCount() );
3941 QString intervalStr = i18nc(
"interval is N days/hours/minutes",
3944 QString repeatStr = i18nc(
"(repeat string, interval string)",
3945 "(%1, %2)", countStr, intervalStr );
3946 remStr = remStr +
' ' + repeatStr;
3949 reminderStringList << remStr;
QString description() const
Returns the incidence description.
QString email() const
Returns the email address for this person.
KCAL_DEPRECATED_EXPORT QString mimeType()
Mime-type of iCalendar.
This file is part of the API for handling calendar data and defines the CalendarLocal class...
QString richDescription() const
Returns the incidence description in rich text format.
bool isReadOnly() const
Returns true the object is read-only; false otherwise.
QList< int > yearMonths() const
Returns the months within a yearly recurrence.
virtual QString subresourceIdentifier(Incidence *incidence)
Get the identifier of the subresource associated with a specified incidence.
KDateTime end() const
Returns when this period ends.
const Attendee::List & attendees() const
Returns a list of incidence attendees.
Provides a To-do in the sense of RFC2445.
Represents the main calendar class.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
An abstract class that provides a common base for all calendar incidence classes. ...
QList< int > yearDays() const
Returns the day numbers within a yearly recurrence.
bool descriptionIsRich() const
Returns true if incidence description contains RichText; false otherwise.
virtual KDateTime dtStart() const
Returns an incidence's starting date/time as a KDateTime.
int repeatCount() const
Returns how many times an alarm may repeats after its initial occurrence.
QList< RecurrenceRule::WDayPos > monthPositions() const
Returns list of day positions in months.
Represents information related to an attendee of an Calendar Incidence, typically a meeting or task (...
This class provides a Calendar which is composed of other Calendars known as "Resources".
This class provides an Event in the sense of RFC2445.
A Scheduling message class.
KDateTime getPreviousDateTime(const KDateTime &afterDateTime) const
Returns the date and time of the last previous recurrence, before the specified date/time.
To-do in process of being completed.
QString uid() const
Returns the unique id (uid) for the incidence.
int frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
bool isAlarmEnabled() const
Returns true if any of the incidence alarms are enabled; false otherwise.
KDateTime::Spec timeSpec() const
Get the time specification (time zone etc.) used for creating or modifying incidences in the Calendar...
virtual KDateTime dtStart() const
QBitArray days() const
Returns week day mask (bit 0 = Monday).
int asSeconds() const
Returns the length of the duration in seconds.
KDateTime dtDue(bool first=false) const
Returns due date and time.
This class provides the interfaces for a calendar resource.
KDateTime created() const
Returns the incidence creation date/time.
QString richLocation() const
Returns the incidence location in rich text format.
PartStat status() const
Returns the PartStat of the attendee.
This class provides the interface for a visitor of calendar components.
bool isCompleted() const
Returns true if the todo is 100% completed, otherwise return false.
virtual void shiftTimes(const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec)
Shift the times of the incidence so that they appear at the same clock time as before but in a new ti...
QString label() const
Returns the attachment label string.
bool isMultiDay(const KDateTime::Spec &spec=KDateTime::Spec()) const
Returns true if the event spans multiple days, otherwise return false.
Event, to-do or journal declined.
QString mimeType() const
Returns the MIME-type of the attachment.
bool isEmpty() const
Returns true if the person name and email address are empty.
bool hasTime() const
Returns true if the alarm has a trigger date/time.
Role
The different types of participation roles.
KDateTime start() const
Returns when this period starts.
structure for describing the n-th weekday of the month/year.
QDate startDate() const
Return the start date/time of the recurrence.
Non-Participant; copied for information purposes.
Duration duration() const
Returns the duration of the period.
bool allDay() const
Returns true or false depending on whether the incidence is all-day.
This file is part of the API for handling calendar data and defines the CalendarResources class...
virtual QByteArray type() const =0
Prints the type of Incidence as a string.
Represents a person, by name ane email address.
This file is part of the API for handling calendar data and defines the Todo class.
Attachment::List attachments() const
Returns a list of all incidence attachments.
bool hasDuration() const
Returns true if this period has a set duration, false if it just has a start and an end...
bool hasEndDate() const
Returns whether the event has an end date/time.
This file is part of the API for handling calendar data and defines the Calendar class.
QString name() const
Returns the person name string.
bool hasStartOffset() const
Returns whether the alarm is defined in terms of an offset relative to the start of the parent Incide...
QString customProperty(const QByteArray &app, const QByteArray &key) const
Return the value of a custom calendar property.
virtual QStringList subresources() const
If this resource has subresources, return a QStringList of them.
Person organizer() const
Returns the Person associated with this incidence.
Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar component...
This class provides a template for lists of pointers.
bool hasEndOffset() const
Returns whether the alarm is defined in terms of an offset relative to the end of the event...
QString richSummary() const
Returns the incidence summary in rich text format.
This file is part of the API for handling calendar data and defines the FreeBusy class.
Represents information related to an attachment for a Calendar Incidence.
bool hasDueDate() const
Returns true if the todo has a due date, otherwise return false.
Provides a Journal in the sense of RFC2445.
IncidenceBase * event()
Returns the event associated with this message.
Duration endOffset() const
Returns offset of alarm in time relative to the end of the event.
ResourceCalendar * resource(Incidence *incidence)
Returns the Resource associated with a specified Incidence.
Duration startOffset() const
Returns offset of alarm in time relative to the start of the parent Incidence.
const Alarm::List & alarms() const
Returns a list of all incidence alarms.
KDateTime endDateTime() const
Returns the date/time of the last recurrence.
QList< int > yearDates() const
Returns the dates within a yearly recurrence.
The period can be defined by either a start time and an end time or by a start time and a duration...
bool locationIsRich() const
Returns true if incidence location contains RichText; false otherwise.
virtual bool accept(Visitor &v)
Accept IncidenceVisitor.
QString uid() const
Returns the UID of the attendee.
This file is part of the API for handling calendar data and defines the Journal class.
QString uri() const
Returns the URI of the attachment.
Event, to-do or journal accepted.
static QString statusName(PartStat status)
Returns the specified PartStat status as a text string.
Event, to-do or journal needs action (default)
virtual QString labelForSubresource(const QString &resource) const
What is the label for this subresource?
QString delegate() const
Returns the delegate.
KDateTime getNextDateTime(const KDateTime &preDateTime) const
Returns the date and time of the next recurrence, after the specified date/time.
QString delegator() const
Returns the delegator.
This file is part of the API for handling calendar data and defines the Attachment class...
Duration snoozeTime() const
Returns the snooze time interval.
Participation is required (default)
Period::List busyPeriods() const
Returns the list of all periods within the free/busy.
Role role() const
Returns the Role of the attendee.
QDate endDate() const
Returns the date of the last recurrence.
This file is part of the API for handling calendar data and defines the Event class.
virtual QString resourceName() const
QString fullName() const
Returns the full name of this person.
bool hasStartDate() const
Returns true if the todo has a start date, otherwise return false.
Participation is optional.
QList< RecurrenceRule::WDayPos > yearPositions() const
Returns the positions within a yearly recurrence.
Recurrence * recurrence() const
Returns the recurrence rule associated with this incidence.
int percentComplete() const
Returns what percentage of the to-do is completed.
iTIPMethod method()
Returns the iTIP method associated with this message.
int priority() const
Returns the incidence priority.
QString statusStr() const
Returns the attendee PartStat as a text string.
bool summaryIsRich() const
Returns true if incidence summary contains RichText; false otherwise.
ushort recurrenceType() const
Returns the event's recurrence status.
QString completedStr(bool shortfmt=false) const
Returns string contaiting date and time when the todo was completed formatted according to the user's...
int revision() const
Returns the number of revisions this incidence has seen.
Event or to-do delegated.
QStringList comments() const
Returns all incidence comments as a list of strings.
QStringList categories() const
Returns the incidence categories as a list of strings.
QString location() const
Returns the incidence location.
KDateTime time() const
Returns the alarm trigger date/time.
virtual bool visit(Event *event)
Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on a...
static QString roleName(Role role)
Returns the specified Role role as a text string.
Provides information about the free/busy time of a calendar.
Represents an alarm notification.
Event or to-do tentatively accepted.
QList< int > monthDays() const
Returns list of day numbers of a month.
virtual KDateTime dtEnd() const
Returns the end datetime for the free/busy.
This class represents a recurrence rule for a calendar incidence.
virtual KDateTime dtEnd() const
Returns the event end date and time.
QString summary() const
Returns the incidence summary.
Attendee * attendeeByMail(const QString &email) const
Returns the attendee with the specified email address.