00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "incidenceformatter.h"
00025
00026 #include <libkcal/attachment.h>
00027 #include <libkcal/calhelper.h>
00028 #include <libkcal/event.h>
00029 #include <libkcal/todo.h>
00030 #include <libkcal/journal.h>
00031 #include <libkcal/calendar.h>
00032 #include <libkcal/calendarlocal.h>
00033 #include <libkcal/icalformat.h>
00034 #include <libkcal/freebusy.h>
00035 #include <libkcal/calendarresources.h>
00036
00037 #include <libemailfunctions/email.h>
00038
00039 #include <ktnef/ktnefparser.h>
00040 #include <ktnef/ktnefmessage.h>
00041 #include <ktnef/ktnefdefs.h>
00042 #include <kabc/phonenumber.h>
00043 #include <kabc/vcardconverter.h>
00044 #include <kabc/stdaddressbook.h>
00045
00046 #include <kapplication.h>
00047 #include <kemailsettings.h>
00048
00049 #include <klocale.h>
00050 #include <kglobal.h>
00051 #include <kiconloader.h>
00052 #include <kcalendarsystem.h>
00053 #include <kmimetype.h>
00054
00055 #include <qbuffer.h>
00056 #include <qstylesheet.h>
00057 #include <qdatetime.h>
00058 #include <qregexp.h>
00059
00060 #include <time.h>
00061
00062 using namespace KCal;
00063
00064
00065
00066
00067
00068 static QString htmlAddLink( const QString &ref, const QString &text,
00069 bool newline = true )
00070 {
00071 QString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
00072 if ( newline ) tmpStr += "\n";
00073 return tmpStr;
00074 }
00075
00076 static QString htmlAddMailtoLink( const QString &email, const QString &name )
00077 {
00078 QString str;
00079
00080 if ( !email.isEmpty() ) {
00081 KCal::Person person( name, email );
00082 KURL mailto;
00083 mailto.setProtocol( "mailto" );
00084 mailto.setPath( person.fullName() );
00085 const QString iconPath = KGlobal::iconLoader()->iconPath( "mail_new", KIcon::Small );
00086 str = htmlAddLink( mailto.url(), "<img valign=\"top\" src=\"" + iconPath + "\">" );
00087 }
00088 return str;
00089 }
00090
00091 static QString htmlAddUidLink( const QString &email, const QString &name, const QString &uid )
00092 {
00093 QString str;
00094
00095 if ( !uid.isEmpty() ) {
00096
00097 if ( name.isEmpty() ) {
00098
00099 str += htmlAddLink( "uid:" + uid, email );
00100 } else {
00101 str += htmlAddLink( "uid:" + uid, name );
00102 }
00103 }
00104 return str;
00105 }
00106
00107 static QString htmlAddTag( const QString & tag, const QString & text )
00108 {
00109 int numLineBreaks = text.contains( "\n" );
00110 QString str = "<" + tag + ">";
00111 QString tmpText = text;
00112 QString tmpStr = str;
00113 if( numLineBreaks >= 0 ) {
00114 if ( numLineBreaks > 0) {
00115 int pos = 0;
00116 QString tmp;
00117 for( int i = 0; i <= numLineBreaks; i++ ) {
00118 pos = tmpText.find( "\n" );
00119 tmp = tmpText.left( pos );
00120 tmpText = tmpText.right( tmpText.length() - pos - 1 );
00121 tmpStr += tmp + "<br>";
00122 }
00123 } else {
00124 tmpStr += tmpText;
00125 }
00126 }
00127 tmpStr += "</" + tag + ">";
00128 return tmpStr;
00129 }
00130
00131 static QPair<QString, QString> searchNameAndUid( const QString &email, const QString &name,
00132 const QString &uid )
00133 {
00134 QString sName = name;
00135 QString sUid = uid;
00136
00137
00138 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
00139 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00140 KABC::Addressee::List addressList = add_book->findByEmail( email );
00141 if ( !addressList.isEmpty() ) {
00142 KABC::Addressee o = addressList.first();
00143 if ( !o.isEmpty() && addressList.size() < 2 ) {
00144 if ( name.isEmpty() ) {
00145
00146 sName = o.formattedName();
00147 }
00148 sUid = o.uid();
00149 } else {
00150
00151 sUid = QString::null;
00152 }
00153 }
00154 }
00155 QPair<QString, QString>s;
00156 s.first = sName;
00157 s.second = sUid;
00158 return s;
00159 }
00160
00161 static QString searchName( const QString &email, const QString &name )
00162 {
00163 QString printName = name;
00164
00165 if ( name.isEmpty() && !email.isEmpty() ) {
00166 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00167 KABC::Addressee::List addressList = add_book->findByEmail( email );
00168 if ( !addressList.isEmpty() ) {
00169 KABC::Addressee o = addressList.first();
00170 if ( !o.isEmpty() && addressList.size() < 2 ) {
00171
00172 printName = o.formattedName();
00173 }
00174 }
00175 }
00176 return printName;
00177 }
00178
00179 static bool iamAttendee( Attendee *attendee )
00180 {
00181
00182
00183 bool iam = false;
00184 KEMailSettings settings;
00185 QStringList profiles = settings.profiles();
00186 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
00187 settings.setProfile( *it );
00188 if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->email() ) {
00189 iam = true;
00190 break;
00191 }
00192 }
00193 return iam;
00194 }
00195
00196 static bool iamOrganizer( Incidence *incidence )
00197 {
00198
00199
00200 if ( !incidence ) {
00201 return false;
00202 }
00203
00204 bool iam = false;
00205 KEMailSettings settings;
00206 QStringList profiles = settings.profiles();
00207 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
00208 settings.setProfile( *it );
00209 if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->organizer().email() ) {
00210 iam = true;
00211 break;
00212 }
00213 }
00214 return iam;
00215 }
00216
00217 static bool senderIsOrganizer( Incidence *incidence, const QString &sender )
00218 {
00219
00220
00221 if ( !incidence || sender.isEmpty() ) {
00222 return true;
00223 }
00224 bool isorg = true;
00225 QString senderName, senderEmail;
00226 if ( KPIM::getNameAndMail( sender, senderName, senderEmail ) ) {
00227
00228 if ( incidence->organizer().email() != senderEmail &&
00229 incidence->organizer().name() != senderName ) {
00230 isorg = false;
00231 }
00232 }
00233 return isorg;
00234 }
00235
00236 static bool attendeeIsOrganizer( Incidence *incidence, Attendee *attendee )
00237 {
00238 if ( incidence && attendee &&
00239 ( incidence->organizer().email() == attendee->email() ) ) {
00240 return true;
00241 } else {
00242 return false;
00243 }
00244 }
00245
00246 static QString firstAttendeeName( Incidence *incidence, const QString &defName )
00247 {
00248 QString name;
00249 if ( !incidence ) {
00250 return name;
00251 }
00252
00253 Attendee::List attendees = incidence->attendees();
00254 if( attendees.count() > 0 ) {
00255 Attendee *attendee = *attendees.begin();
00256 name = attendee->name();
00257 if ( name.isEmpty() ) {
00258 name = attendee->email();
00259 }
00260 if ( name.isEmpty() ) {
00261 name = defName;
00262 }
00263 }
00264 return name;
00265 }
00266
00267 static QString rsvpStatusIconPath( Attendee::PartStat status )
00268 {
00269 QString iconPath;
00270 switch ( status ) {
00271 case Attendee::Accepted:
00272 iconPath = KGlobal::iconLoader()->iconPath( "ok", KIcon::Small );
00273 break;
00274 case Attendee::Declined:
00275 iconPath = KGlobal::iconLoader()->iconPath( "no", KIcon::Small );
00276 break;
00277 case Attendee::NeedsAction:
00278 case Attendee::InProcess:
00279 iconPath = KGlobal::iconLoader()->iconPath( "help", KIcon::Small );
00280 break;
00281 case Attendee::Tentative:
00282 iconPath = KGlobal::iconLoader()->iconPath( "apply", KIcon::Small );
00283 break;
00284 case Attendee::Delegated:
00285 iconPath = KGlobal::iconLoader()->iconPath( "mail_forward", KIcon::Small );
00286 break;
00287 default:
00288 break;
00289 }
00290 return iconPath;
00291 }
00292
00293
00294
00295
00296
00297 static QString displayViewFormatPerson( const QString &email, const QString &name,
00298 const QString &uid, const QString &iconPath )
00299 {
00300
00301 QPair<QString, QString> s = searchNameAndUid( email, name, uid );
00302 const QString printName = s.first;
00303 const QString printUid = s.second;
00304
00305 QString personString;
00306 if ( !iconPath.isEmpty() ) {
00307 personString += "<img valign=\"top\" src=\"" + iconPath + "\">" + " ";
00308 }
00309
00310
00311 if ( !printUid.isEmpty() ) {
00312 personString += htmlAddUidLink( email, printName, printUid );
00313 } else {
00314
00315 personString += ( printName.isEmpty() ? email : printName );
00316 }
00317
00318
00319 if ( !email.isEmpty() ) {
00320 personString += " " + htmlAddMailtoLink( email, printName );
00321 }
00322
00323 return personString;
00324 }
00325
00326 static QString displayViewFormatPerson( const QString &email, const QString &name,
00327 const QString &uid, Attendee::PartStat status )
00328 {
00329 return displayViewFormatPerson( email, name, uid, rsvpStatusIconPath( status ) );
00330 }
00331
00332 static QString displayViewFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role,
00333 bool showStatus )
00334 {
00335 QString tmpStr;
00336 Attendee::List::ConstIterator it;
00337 Attendee::List attendees = incidence->attendees();
00338
00339 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00340 Attendee *a = *it;
00341 if ( a->role() != role ) {
00342
00343 continue;
00344 }
00345 if ( attendeeIsOrganizer( incidence, a ) ) {
00346
00347 continue;
00348 }
00349 tmpStr += displayViewFormatPerson( a->email(), a->name(), a->uid(),
00350 showStatus ? a->status() : Attendee::None );
00351 if ( !a->delegator().isEmpty() ) {
00352 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
00353 }
00354 if ( !a->delegate().isEmpty() ) {
00355 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
00356 }
00357 tmpStr += "<br>";
00358 }
00359 if ( tmpStr.endsWith( "<br>" ) ) {
00360 tmpStr.truncate( tmpStr.length() - 4 );
00361 }
00362 return tmpStr;
00363 }
00364
00365 static QString displayViewFormatAttendees( Calendar *calendar, Incidence *incidence )
00366 {
00367 QString tmpStr, str;
00368
00369
00370 int attendeeCount = incidence->attendees().count();
00371 if ( attendeeCount > 1 ||
00372 ( attendeeCount == 1 &&
00373 !attendeeIsOrganizer( incidence, incidence->attendees().first() ) ) ) {
00374
00375 QPair<QString, QString> s = searchNameAndUid( incidence->organizer().email(),
00376 incidence->organizer().name(),
00377 QString() );
00378 tmpStr += "<tr>";
00379 tmpStr += "<td><b>" + i18n( "Organizer:" ) + "</b></td>";
00380 QString iconPath = KGlobal::iconLoader()->iconPath( "organizer", KIcon::Small );
00381 tmpStr += "<td>" + displayViewFormatPerson( incidence->organizer().email(),
00382 s.first, s.second, iconPath ) +
00383 "</td>";
00384 tmpStr += "</tr>";
00385 }
00386
00387
00388
00389 bool showStatus = CalHelper::incOrganizerOwnsCalendar( calendar, incidence );
00390
00391
00392 str = displayViewFormatAttendeeRoleList( incidence, Attendee::Chair, showStatus );
00393 if ( !str.isEmpty() ) {
00394 tmpStr += "<tr>";
00395 tmpStr += "<td><b>" + i18n( "Chair:" ) + "</b></td>";
00396 tmpStr += "<td>" + str + "</td>";
00397 tmpStr += "</tr>";
00398 }
00399
00400
00401 str = displayViewFormatAttendeeRoleList( incidence, Attendee::ReqParticipant, showStatus );
00402 if ( !str.isEmpty() ) {
00403 tmpStr += "<tr>";
00404 tmpStr += "<td><b>" + i18n( "Required Participants:" ) + "</b></td>";
00405 tmpStr += "<td>" + str + "</td>";
00406 tmpStr += "</tr>";
00407 }
00408
00409
00410 str = displayViewFormatAttendeeRoleList( incidence, Attendee::OptParticipant, showStatus );
00411 if ( !str.isEmpty() ) {
00412 tmpStr += "<tr>";
00413 tmpStr += "<td><b>" + i18n( "Optional Participants:" ) + "</b></td>";
00414 tmpStr += "<td>" + str + "</td>";
00415 tmpStr += "</tr>";
00416 }
00417
00418
00419 str = displayViewFormatAttendeeRoleList( incidence, Attendee::NonParticipant, showStatus );
00420 if ( !str.isEmpty() ) {
00421 tmpStr += "<tr>";
00422 tmpStr += "<td><b>" + i18n( "Observers:" ) + "</b></td>";
00423 tmpStr += "<td>" + str + "</td>";
00424 tmpStr += "</tr>";
00425 }
00426
00427 return tmpStr;
00428 }
00429
00430 static QString displayViewFormatAttachments( Incidence *incidence )
00431 {
00432 QString tmpStr;
00433 Attachment::List as = incidence->attachments();
00434 Attachment::List::ConstIterator it;
00435 uint count = 0;
00436 for( it = as.begin(); it != as.end(); ++it ) {
00437 count++;
00438 if ( (*it)->isUri() ) {
00439 QString name;
00440 if ( (*it)->uri().startsWith( "kmail:" ) ) {
00441 name = i18n( "Show mail" );
00442 } else {
00443 if ( (*it)->label().isEmpty() ) {
00444 name = (*it)->uri();
00445 } else {
00446 name = (*it)->label();
00447 }
00448 }
00449 tmpStr += htmlAddLink( (*it)->uri(), name );
00450 } else {
00451 tmpStr += htmlAddLink( "ATTACH:" + incidence->uid() + ':' + (*it)->label(),
00452 (*it)->label(), false );
00453 }
00454 if ( count < as.count() ) {
00455 tmpStr += "<br>";
00456 }
00457 }
00458 return tmpStr;
00459 }
00460
00461 static QString displayViewFormatCategories( Incidence *incidence )
00462 {
00463
00464 return incidence->categories().join( ", " );
00465 }
00466
00467 static QString displayViewFormatCreationDate( Incidence *incidence )
00468 {
00469 return i18n( "Creation date: %1" ).
00470 arg( IncidenceFormatter::dateTimeToString( incidence->created(), false, true ) );
00471 }
00472
00473 static QString displayViewFormatBirthday( Event *event )
00474 {
00475 if ( !event ) {
00476 return QString::null;
00477 }
00478 if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) {
00479 return QString::null;
00480 }
00481
00482 QString uid = event->customProperty("KABC","UID-1");
00483 QString name = event->customProperty("KABC","NAME-1");
00484 QString email= event->customProperty("KABC","EMAIL-1");
00485 QString tmpStr = displayViewFormatPerson( email, name, uid, QString() );
00486
00487 if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
00488 uid = event->customProperty("KABC","UID-2");
00489 name = event->customProperty("KABC","NAME-2");
00490 email= event->customProperty("KABC","EMAIL-2");
00491 tmpStr += "<br>" + displayViewFormatPerson( email, name, uid, QString() );
00492 }
00493
00494 return tmpStr;
00495 }
00496
00497 static QString displayViewFormatHeader( Incidence *incidence )
00498 {
00499 QString tmpStr = "<table><tr>";
00500
00501
00502 {
00503 tmpStr += "<td>";
00504
00505 if ( incidence->type() == "Event" ) {
00506 QString iconPath;
00507 if ( incidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
00508 if ( incidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
00509 iconPath =
00510 KGlobal::iconLoader()->iconPath( "calendaranniversary", KIcon::Small );
00511 } else {
00512 iconPath = KGlobal::iconLoader()->iconPath( "calendarbirthday", KIcon::Small );
00513 }
00514 } else {
00515 iconPath = KGlobal::iconLoader()->iconPath( "appointment", KIcon::Small );
00516 }
00517 tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
00518 }
00519 if ( incidence->type() == "Todo" ) {
00520 tmpStr += "<img valign=\"top\" src=\"" +
00521 KGlobal::iconLoader()->iconPath( "todo", KIcon::Small ) +
00522 "\">";
00523 }
00524 if ( incidence->type() == "Journal" ) {
00525 tmpStr += "<img valign=\"top\" src=\"" +
00526 KGlobal::iconLoader()->iconPath( "journal", KIcon::Small ) +
00527 "\">";
00528 }
00529 if ( incidence->isAlarmEnabled() ) {
00530 tmpStr += "<img valign=\"top\" src=\"" +
00531 KGlobal::iconLoader()->iconPath( "bell", KIcon::Small ) +
00532 "\">";
00533 }
00534 if ( incidence->doesRecur() ) {
00535 tmpStr += "<img valign=\"top\" src=\"" +
00536 KGlobal::iconLoader()->iconPath( "recur", KIcon::Small ) +
00537 "\">";
00538 }
00539 if ( incidence->isReadOnly() ) {
00540 tmpStr += "<img valign=\"top\" src=\"" +
00541 KGlobal::iconLoader()->iconPath( "readonlyevent", KIcon::Small ) +
00542 "\">";
00543 }
00544
00545 tmpStr += "</td>";
00546 }
00547
00548 tmpStr += "<td>";
00549 tmpStr += "<b><u>" + incidence->summary() + "</u></b>";
00550 tmpStr += "</td>";
00551
00552 tmpStr += "</tr></table>";
00553
00554 return tmpStr;
00555 }
00556
00557 static QString displayViewFormatEvent( Calendar *calendar, Event *event, const QDate &date )
00558 {
00559 if ( !event ) {
00560 return QString::null;
00561 }
00562
00563 QString tmpStr = displayViewFormatHeader( event );
00564
00565 tmpStr += "<table>";
00566 tmpStr += "<col width=\"25%\"/>";
00567 tmpStr += "<col width=\"75%\"/>";
00568
00569 if ( calendar ) {
00570 QString calStr = IncidenceFormatter::resourceString( calendar, event );
00571 if ( !calStr.isEmpty() ) {
00572 tmpStr += "<tr>";
00573 tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
00574 tmpStr += "<td>" + calStr + "</td>";
00575 tmpStr += "</tr>";
00576 }
00577 }
00578
00579 if ( !event->location().isEmpty() ) {
00580 tmpStr += "<tr>";
00581 tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
00582 tmpStr += "<td>" + event->location() + "</td>";
00583 tmpStr += "</tr>";
00584 }
00585
00586 QDateTime startDt = event->dtStart();
00587 QDateTime endDt = event->dtEnd();
00588 if ( event->doesRecur() ) {
00589 if ( date.isValid() ) {
00590 QDateTime dt( date, QTime( 0, 0, 0 ) );
00591 int diffDays = startDt.daysTo( dt );
00592 dt = dt.addSecs( -1 );
00593 startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
00594 if ( event->hasEndDate() ) {
00595 endDt = endDt.addDays( diffDays );
00596 if ( startDt > endDt ) {
00597 startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
00598 endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
00599 }
00600 }
00601 }
00602 }
00603
00604 tmpStr += "<tr>";
00605 if ( event->doesFloat() ) {
00606 if ( event->isMultiDay() ) {
00607 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
00608 tmpStr += "<td>" +
00609 i18n("<beginDate> - <endDate>","%1 - %2").
00610 arg( IncidenceFormatter::dateToString( startDt, false ) ).
00611 arg( IncidenceFormatter::dateToString( endDt, false ) ) +
00612 "</td>";
00613 } else {
00614 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
00615 tmpStr += "<td>" +
00616 i18n("date as string","%1").
00617 arg( IncidenceFormatter::dateToString( startDt, false ) ) +
00618 "</td>";
00619 }
00620 } else {
00621 if ( event->isMultiDay() ) {
00622 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
00623 tmpStr += "<td>" +
00624 i18n("<beginDate> - <endDate>","%1 - %2").
00625 arg( IncidenceFormatter::dateToString( startDt, false ) ).
00626 arg( IncidenceFormatter::dateToString( endDt, false ) ) +
00627 "</td>";
00628 } else {
00629 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
00630 tmpStr += "<td>" +
00631 i18n("date as string","%1").
00632 arg( IncidenceFormatter::dateToString( startDt, false ) ) +
00633 "</td>";
00634
00635 tmpStr += "</tr><tr>";
00636 tmpStr += "<td><b>" + i18n( "Time:" ) + "</b></td>";
00637 if ( event->hasEndDate() && startDt != endDt ) {
00638 tmpStr += "<td>" +
00639 i18n("<beginTime> - <endTime>","%1 - %2").
00640 arg( IncidenceFormatter::timeToString( startDt, true ) ).
00641 arg( IncidenceFormatter::timeToString( endDt, true ) ) +
00642 "</td>";
00643 } else {
00644 tmpStr += "<td>" +
00645 IncidenceFormatter::timeToString( startDt, true ) +
00646 "</td>";
00647 }
00648 }
00649 }
00650 tmpStr += "</tr>";
00651
00652 const QString durStr = IncidenceFormatter::durationString( event );
00653 if ( !durStr.isEmpty() ) {
00654 tmpStr += "<tr>";
00655 tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
00656 tmpStr += "<td>" + durStr + "</td>";
00657 tmpStr += "</tr>";
00658 }
00659
00660 if ( event->doesRecur() ) {
00661 tmpStr += "<tr>";
00662 tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
00663 tmpStr += "<td>" +
00664 IncidenceFormatter::recurrenceString( event ) +
00665 "</td>";
00666 tmpStr += "</tr>";
00667 }
00668
00669 if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
00670 tmpStr += "<tr>";
00671 if ( event->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
00672 tmpStr += "<td><b>" + i18n( "Anniversary:" ) + "</b></td>";
00673 } else {
00674 tmpStr += "<td><b>" + i18n( "Birthday:" ) + "</b></td>";
00675 }
00676 tmpStr += "<td>" + displayViewFormatBirthday( event ) + "</td>";
00677 tmpStr += "</tr>";
00678 tmpStr += "</table>";
00679 return tmpStr;
00680 }
00681
00682 if ( !event->description().isEmpty() ) {
00683 tmpStr += "<tr>";
00684 tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
00685 tmpStr += "<td>" + event->description() + "</td>";
00686 tmpStr += "</tr>";
00687 }
00688
00689
00690
00691 int reminderCount = event->alarms().count();
00692 if ( reminderCount > 0 && event->isAlarmEnabled() ) {
00693 tmpStr += "<tr>";
00694 tmpStr += "<td><b>" +
00695 i18n( "Reminder:", "%n Reminders:", reminderCount ) +
00696 "</b></td>";
00697 tmpStr += "<td>" + IncidenceFormatter::reminderStringList( event ).join( "<br>" ) + "</td>";
00698 tmpStr += "</tr>";
00699 }
00700
00701 tmpStr += displayViewFormatAttendees( calendar, event );
00702
00703 int categoryCount = event->categories().count();
00704 if ( categoryCount > 0 ) {
00705 tmpStr += "<tr>";
00706 tmpStr += "<td><b>" +
00707 i18n( "Category:", "%n Categories:", categoryCount ) +
00708 "</b></td>";
00709 tmpStr += "<td>" + displayViewFormatCategories( event ) + "</td>";
00710 tmpStr += "</tr>";
00711 }
00712
00713 int attachmentCount = event->attachments().count();
00714 if ( attachmentCount > 0 ) {
00715 tmpStr += "<tr>";
00716 tmpStr += "<td><b>" +
00717 i18n( "Attachment:", "%n Attachments:", attachmentCount ) +
00718 "</b></td>";
00719 tmpStr += "<td>" + displayViewFormatAttachments( event ) + "</td>";
00720 tmpStr += "</tr>";
00721 }
00722 tmpStr += "</table>";
00723
00724 tmpStr += "<em>" + displayViewFormatCreationDate( event ) + "</em>";
00725
00726 return tmpStr;
00727 }
00728
00729 static QString displayViewFormatTodo( Calendar *calendar, Todo *todo,
00730 const QDate &date )
00731 {
00732 if ( !todo ) {
00733 return QString::null;
00734 }
00735
00736 QString tmpStr = displayViewFormatHeader( todo );
00737
00738 tmpStr += "<table>";
00739 tmpStr += "<col width=\"25%\"/>";
00740 tmpStr += "<col width=\"75%\"/>";
00741
00742 if ( calendar ) {
00743 const QString calStr = IncidenceFormatter::resourceString( calendar, todo );
00744 if ( !calStr.isEmpty() ) {
00745 tmpStr += "<tr>";
00746 tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
00747 tmpStr += "<td>" + calStr + "</td>";
00748 tmpStr += "</tr>";
00749 }
00750 }
00751
00752 if ( !todo->location().isEmpty() ) {
00753 tmpStr += "<tr>";
00754 tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
00755 tmpStr += "<td>" + todo->location() + "</td>";
00756 tmpStr += "</tr>";
00757 }
00758
00759 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
00760 QDateTime startDt = todo->dtStart();
00761 if ( todo->doesRecur() ) {
00762 if ( date.isValid() ) {
00763 startDt.setDate( date );
00764 }
00765 }
00766 tmpStr += "<tr>";
00767 tmpStr += "<td><b>" + i18n( "Start:" ) + "</b></td>";
00768 tmpStr += "<td>" +
00769 IncidenceFormatter::dateTimeToString( startDt,
00770 todo->doesFloat(), false ) +
00771 "</td>";
00772 tmpStr += "</tr>";
00773 }
00774
00775 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
00776 QDateTime dueDt = todo->dtDue();
00777 if ( todo->doesRecur() ) {
00778 if ( date.isValid() ) {
00779 QDateTime dt( date, QTime( 0, 0, 0 ) );
00780 dt = dt.addSecs( -1 );
00781 dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
00782 }
00783 }
00784 tmpStr += "<tr>";
00785 tmpStr += "<td><b>" + i18n( "Due:" ) + "</b></td>";
00786 tmpStr += "<td>" +
00787 IncidenceFormatter::dateTimeToString( dueDt,
00788 todo->doesFloat(), false ) +
00789 "</td>";
00790 tmpStr += "</tr>";
00791 }
00792
00793 const QString durStr = IncidenceFormatter::durationString( todo );
00794 if ( !durStr.isEmpty() ) {
00795 tmpStr += "<tr>";
00796 tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
00797 tmpStr += "<td>" + durStr + "</td>";
00798 tmpStr += "</tr>";
00799 }
00800
00801 if ( todo->doesRecur() ) {
00802 tmpStr += "<tr>";
00803 tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
00804 tmpStr += "<td>" +
00805 IncidenceFormatter::recurrenceString( todo ) +
00806 "</td>";
00807 tmpStr += "</tr>";
00808 }
00809
00810 if ( !todo->description().isEmpty() ) {
00811 tmpStr += "<tr>";
00812 tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
00813 tmpStr += "<td>" + todo->description() + "</td>";
00814 tmpStr += "</tr>";
00815 }
00816
00817
00818
00819 int reminderCount = todo->alarms().count();
00820 if ( reminderCount > 0 && todo->isAlarmEnabled() ) {
00821 tmpStr += "<tr>";
00822 tmpStr += "<td><b>" +
00823 i18n( "Reminder:", "%n Reminders:", reminderCount ) +
00824 "</b></td>";
00825 tmpStr += "<td>" + IncidenceFormatter::reminderStringList( todo ).join( "<br>" ) + "</td>";
00826 tmpStr += "</tr>";
00827 }
00828
00829 tmpStr += displayViewFormatAttendees( calendar, todo );
00830
00831 int categoryCount = todo->categories().count();
00832 if ( categoryCount > 0 ) {
00833 tmpStr += "<tr>";
00834 tmpStr += "<td><b>" +
00835 i18n( "Category:", "%n Categories:", categoryCount ) +
00836 "</b></td>";
00837 tmpStr += "<td>" + displayViewFormatCategories( todo ) + "</td>";
00838 tmpStr += "</tr>";
00839 }
00840
00841 if ( todo->priority() > 0 ) {
00842 tmpStr += "<tr>";
00843 tmpStr += "<td><b>" + i18n( "Priority:" ) + "</b></td>";
00844 tmpStr += "<td>";
00845 tmpStr += QString::number( todo->priority() );
00846 tmpStr += "</td>";
00847 tmpStr += "</tr>";
00848 }
00849
00850 tmpStr += "<tr>";
00851 if ( todo->isCompleted() ) {
00852 tmpStr += "<td><b>" + i18n( "Completed:" ) + "</b></td>";
00853 tmpStr += "<td>";
00854 tmpStr += todo->completedStr();
00855 } else {
00856 tmpStr += "<td><b>" + i18n( "Percent Done:" ) + "</b></td>";
00857 tmpStr += "<td>";
00858 tmpStr += i18n( "%1%" ).arg( todo->percentComplete() );
00859 }
00860 tmpStr += "</td>";
00861 tmpStr += "</tr>";
00862
00863 int attachmentCount = todo->attachments().count();
00864 if ( attachmentCount > 0 ) {
00865 tmpStr += "<tr>";
00866 tmpStr += "<td><b>" +
00867 i18n( "Attachment:", "Attachments:", attachmentCount ) +
00868 "</b></td>";
00869 tmpStr += "<td>" + displayViewFormatAttachments( todo ) + "</td>";
00870 tmpStr += "</tr>";
00871 }
00872
00873 tmpStr += "</table>";
00874
00875 tmpStr += "<em>" + displayViewFormatCreationDate( todo ) + "</em>";
00876
00877 return tmpStr;
00878 }
00879
00880 static QString displayViewFormatJournal( Calendar *calendar, Journal *journal )
00881 {
00882 if ( !journal ) {
00883 return QString::null;
00884 }
00885
00886 QString tmpStr = displayViewFormatHeader( journal );
00887
00888 tmpStr += "<table>";
00889 tmpStr += "<col width=\"25%\"/>";
00890 tmpStr += "<col width=\"75%\"/>";
00891
00892 if ( calendar ) {
00893 const QString calStr = IncidenceFormatter::resourceString( calendar, journal );
00894 if ( !calStr.isEmpty() ) {
00895 tmpStr += "<tr>";
00896 tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
00897 tmpStr += "<td>" + calStr + "</td>";
00898 tmpStr += "</tr>";
00899 }
00900 }
00901
00902 tmpStr += "<tr>";
00903 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
00904 tmpStr += "<td>" +
00905 IncidenceFormatter::dateToString( journal->dtStart(), false ) +
00906 "</td>";
00907 tmpStr += "</tr>";
00908
00909 if ( !journal->description().isEmpty() ) {
00910 tmpStr += "<tr>";
00911 tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
00912 tmpStr += "<td>" + journal->description() + "</td>";
00913 tmpStr += "</tr>";
00914 }
00915
00916 int categoryCount = journal->categories().count();
00917 if ( categoryCount > 0 ) {
00918 tmpStr += "<tr>";
00919 tmpStr += "<td><b>" +
00920 i18n( "Category:", "%n Categories:", categoryCount ) +
00921 "</b></td>";
00922 tmpStr += "<td>" + displayViewFormatCategories( journal ) + "</td>";
00923 tmpStr += "</tr>";
00924 }
00925 tmpStr += "</table>";
00926
00927 tmpStr += "<em>" + displayViewFormatCreationDate( journal ) + "</em>";
00928
00929 return tmpStr;
00930 }
00931
00932 static QString displayViewFormatFreeBusy( Calendar * , FreeBusy *fb )
00933 {
00934 if ( !fb ) {
00935 return QString::null;
00936 }
00937
00938 QString tmpStr = htmlAddTag( "h2",
00939 htmlAddTag( "b",
00940 i18n("Free/Busy information for %1").
00941 arg( fb->organizer().fullName() ) ) );
00942
00943 tmpStr += htmlAddTag( "h4", i18n("Busy times in date range %1 - %2:").
00944 arg( IncidenceFormatter::dateToString( fb->dtStart(), true ) ).
00945 arg( IncidenceFormatter::dateToString( fb->dtEnd(), true ) ) );
00946
00947 QValueList<Period> periods = fb->busyPeriods();
00948
00949 QString text = htmlAddTag( "em", htmlAddTag( "b", i18n("Busy:") ) );
00950 QValueList<Period>::iterator it;
00951 for ( it = periods.begin(); it != periods.end(); ++it ) {
00952 Period per = *it;
00953 if ( per.hasDuration() ) {
00954 int dur = per.duration().asSeconds();
00955 QString cont;
00956 if ( dur >= 3600 ) {
00957 cont += i18n("1 hour ", "%n hours ", dur / 3600 );
00958 dur %= 3600;
00959 }
00960 if ( dur >= 60 ) {
00961 cont += i18n("1 minute ", "%n minutes ", dur / 60);
00962 dur %= 60;
00963 }
00964 if ( dur > 0 ) {
00965 cont += i18n("1 second", "%n seconds", dur);
00966 }
00967 text += i18n("startDate for duration", "%1 for %2").
00968 arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
00969 arg( cont );
00970 text += "<br>";
00971 } else {
00972 if ( per.start().date() == per.end().date() ) {
00973 text += i18n("date, fromTime - toTime ", "%1, %2 - %3").
00974 arg( IncidenceFormatter::dateToString( per.start().date(), true ) ).
00975 arg( IncidenceFormatter::timeToString( per.start(), true ) ).
00976 arg( IncidenceFormatter::timeToString( per.end(), true ) );
00977 } else {
00978 text += i18n("fromDateTime - toDateTime", "%1 - %2").
00979 arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
00980 arg( IncidenceFormatter::dateTimeToString( per.end(), false, true ) );
00981 }
00982 text += "<br>";
00983 }
00984 }
00985 tmpStr += htmlAddTag( "p", text );
00986 return tmpStr;
00987 }
00988
00989 class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
00990 {
00991 public:
00992 EventViewerVisitor()
00993 : mCalendar( 0 ), mResult( "" ) {}
00994
00995 bool act( Calendar *calendar, IncidenceBase *incidence, const QDate &date )
00996 {
00997 mCalendar = calendar;
00998 mDate = date;
00999 mResult = "";
01000 return incidence->accept( *this );
01001 }
01002 QString result() const { return mResult; }
01003
01004 protected:
01005 bool visit( Event *event )
01006 {
01007 mResult = displayViewFormatEvent( mCalendar, event, mDate );
01008 return !mResult.isEmpty();
01009 }
01010 bool visit( Todo *todo )
01011 {
01012 mResult = displayViewFormatTodo( mCalendar, todo, mDate );
01013 return !mResult.isEmpty();
01014 }
01015 bool visit( Journal *journal )
01016 {
01017 mResult = displayViewFormatJournal( mCalendar, journal );
01018 return !mResult.isEmpty();
01019 }
01020 bool visit( FreeBusy *fb )
01021 {
01022 mResult = displayViewFormatFreeBusy( mCalendar, fb );
01023 return !mResult.isEmpty();
01024 }
01025
01026 protected:
01027 Calendar *mCalendar;
01028 QDate mDate;
01029 QString mResult;
01030 };
01031
01032 QString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
01033 {
01034 return extensiveDisplayStr( 0, incidence, QDate() );
01035 }
01036
01037 QString IncidenceFormatter::extensiveDisplayStr( Calendar *calendar,
01038 IncidenceBase *incidence,
01039 const QDate &date )
01040 {
01041 if ( !incidence ) {
01042 return QString::null;
01043 }
01044
01045 EventViewerVisitor v;
01046 if ( v.act( calendar, incidence, date ) ) {
01047 return v.result();
01048 } else {
01049 return QString::null;
01050 }
01051 }
01052
01053
01054
01055
01056
01057 static QString string2HTML( const QString& str )
01058 {
01059 return QStyleSheet::convertFromPlainText(str, QStyleSheetItem::WhiteSpaceNormal);
01060 }
01061
01062 static QString cleanHtml( const QString &html )
01063 {
01064 QRegExp rx( "<body[^>]*>(.*)</body>" );
01065 rx.setCaseSensitive( false );
01066 rx.search( html );
01067 QString body = rx.cap( 1 );
01068
01069 return QStyleSheet::escape( body.remove( QRegExp( "<[^>]*>" ) ).stripWhiteSpace() );
01070 }
01071
01072 static QString invitationSummary( Incidence *incidence, bool noHtmlMode )
01073 {
01074 QString summaryStr = i18n( "Summary unspecified" );
01075 if ( !incidence->summary().isEmpty() ) {
01076 if ( !QStyleSheet::mightBeRichText( incidence->summary() ) ) {
01077 summaryStr = QStyleSheet::escape( incidence->summary() );
01078 } else {
01079 summaryStr = incidence->summary();
01080 if ( noHtmlMode ) {
01081 summaryStr = cleanHtml( summaryStr );
01082 }
01083 }
01084 }
01085 return summaryStr;
01086 }
01087
01088 static QString invitationLocation( Incidence *incidence, bool noHtmlMode )
01089 {
01090 QString locationStr = i18n( "Location unspecified" );
01091 if ( !incidence->location().isEmpty() ) {
01092 if ( !QStyleSheet::mightBeRichText( incidence->location() ) ) {
01093 locationStr = QStyleSheet::escape( incidence->location() );
01094 } else {
01095 locationStr = incidence->location();
01096 if ( noHtmlMode ) {
01097 locationStr = cleanHtml( locationStr );
01098 }
01099 }
01100 }
01101 return locationStr;
01102 }
01103
01104 static QString eventStartTimeStr( Event *event )
01105 {
01106 QString tmp;
01107 if ( !event->doesFloat() ) {
01108 tmp = i18n( "%1: Start Date, %2: Start Time", "%1 %2" ).
01109 arg( IncidenceFormatter::dateToString( event->dtStart(), true ),
01110 IncidenceFormatter::timeToString( event->dtStart(), true ) );
01111 } else {
01112 tmp = i18n( "%1: Start Date", "%1 (all day)" ).
01113 arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
01114 }
01115 return tmp;
01116 }
01117
01118 static QString eventEndTimeStr( Event *event )
01119 {
01120 QString tmp;
01121 if ( event->hasEndDate() && event->dtEnd().isValid() ) {
01122 if ( !event->doesFloat() ) {
01123 tmp = i18n( "%1: End Date, %2: End Time", "%1 %2" ).
01124 arg( IncidenceFormatter::dateToString( event->dtEnd(), true ),
01125 IncidenceFormatter::timeToString( event->dtEnd(), true ) );
01126 } else {
01127 tmp = i18n( "%1: End Date", "%1 (all day)" ).
01128 arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
01129 }
01130 }
01131 return tmp;
01132 }
01133
01134 static QString htmlInvitationDetailsBegin()
01135 {
01136 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
01137 return QString( "<div dir=\"%1\">\n" ).arg( dir );
01138 }
01139
01140 static QString htmlInvitationDetailsEnd()
01141 {
01142 return "</div>\n";
01143 }
01144
01145 static QString htmlInvitationDetailsTableBegin()
01146 {
01147 return "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
01148 }
01149
01150 static QString htmlInvitationDetailsTableEnd()
01151 {
01152 return "</table>\n";
01153 }
01154
01155 static QString htmlRow( const QString &title, const QString &value )
01156 {
01157 if ( !value.isEmpty() ) {
01158 return "<tr><td>" + title + "</td><td>" + value + "</td></tr>\n";
01159 } else {
01160 return QString::null;
01161 }
01162 }
01163
01164 static QString htmlRow( const QString &title, const QString &value, const QString &oldvalue )
01165 {
01166
01167 if ( value.isEmpty() ) {
01168 return QString::null;
01169 }
01170
01171
01172 if ( oldvalue.isEmpty() || value == oldvalue ) {
01173 return htmlRow( title, value );
01174 }
01175
01176
01177
01178 QString color = QColor( Qt::red ).name() ;
01179 QString newtitle = "<font color=\"" + color + "\">" + title + "</font>";
01180 QString newvalue = "<font color=\"" + color + "\">" + value + "</font>" +
01181 " " +
01182 "(<strike>" + oldvalue + "</strike>)";
01183 return htmlRow( newtitle, newvalue );
01184 }
01185
01186 static Attendee *findDelegatedFromMyAttendee( Incidence *incidence )
01187 {
01188
01189
01190 Attendee *attendee = 0;
01191 if ( !incidence ) {
01192 return attendee;
01193 }
01194
01195 KEMailSettings settings;
01196 QStringList profiles = settings.profiles();
01197 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
01198 settings.setProfile( *it );
01199
01200 QString delegatorName, delegatorEmail;
01201 Attendee::List attendees = incidence->attendees();
01202 Attendee::List::ConstIterator it2;
01203 for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
01204 Attendee *a = *it2;
01205 KPIM::getNameAndMail( a->delegator(), delegatorName, delegatorEmail );
01206 if ( settings.getSetting( KEMailSettings::EmailAddress ) == delegatorEmail ) {
01207 attendee = a;
01208 break;
01209 }
01210 }
01211 }
01212 return attendee;
01213 }
01214
01215 static Attendee *findMyAttendee( Incidence *incidence )
01216 {
01217
01218
01219 Attendee *attendee = 0;
01220 if ( !incidence ) {
01221 return attendee;
01222 }
01223
01224 KEMailSettings settings;
01225 QStringList profiles = settings.profiles();
01226 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
01227 settings.setProfile( *it );
01228
01229 Attendee::List attendees = incidence->attendees();
01230 Attendee::List::ConstIterator it2;
01231 for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
01232 Attendee *a = *it2;
01233 if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->email() ) {
01234 attendee = a;
01235 break;
01236 }
01237 }
01238 }
01239 return attendee;
01240 }
01241
01242 static Attendee *findAttendee( Incidence *incidence, const QString &email )
01243 {
01244
01245
01246 Attendee *attendee = 0;
01247 if ( !incidence ) {
01248 return attendee;
01249 }
01250
01251 Attendee::List attendees = incidence->attendees();
01252 Attendee::List::ConstIterator it;
01253 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
01254 Attendee *a = *it;
01255 if ( email == a->email() ) {
01256 attendee = a;
01257 break;
01258 }
01259 }
01260 return attendee;
01261 }
01262
01263 static bool rsvpRequested( Incidence *incidence )
01264 {
01265 if ( !incidence ) {
01266 return false;
01267 }
01268
01269
01270
01271 bool rsvp = true;
01272 Attendee::List attendees = incidence->attendees();
01273 Attendee::List::ConstIterator it;
01274 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
01275 if ( it == attendees.begin() ) {
01276 rsvp = (*it)->RSVP();
01277 } else {
01278 if ( (*it)->RSVP() != rsvp ) {
01279 rsvp = true;
01280 break;
01281 }
01282 }
01283 }
01284 return rsvp;
01285 }
01286
01287 static QString rsvpRequestedStr( bool rsvpRequested, const QString &role )
01288 {
01289 if ( rsvpRequested ) {
01290 if ( role.isEmpty() ) {
01291 return i18n( "Your response is requested" );
01292 } else {
01293 return i18n( "Your response as <b>%1</b> is requested" ).arg( role );
01294 }
01295 } else {
01296 if ( role.isEmpty() ) {
01297 return i18n( "No response is necessary" );
01298 } else {
01299 return i18n( "No response as <b>%1</b> is necessary" ).arg( role );
01300 }
01301 }
01302 }
01303
01304 static QString myStatusStr( Incidence *incidence )
01305 {
01306 QString ret;
01307 Attendee *a = findMyAttendee( incidence );
01308 if ( a &&
01309 a->status() != Attendee::NeedsAction && a->status() != Attendee::Delegated ) {
01310 ret = i18n( "(<b>Note</b>: the Organizer preset your response to <b>%1</b>)" ).
01311 arg( Attendee::statusName( a->status() ) );
01312 }
01313 return ret;
01314 }
01315
01316 static QString invitationPerson( const QString &email, const QString &name, const QString &uid )
01317 {
01318 QPair<QString, QString> s = searchNameAndUid( email, name, uid );
01319 const QString printName = s.first;
01320 const QString printUid = s.second;
01321
01322 QString personString;
01323
01324 if ( !printUid.isEmpty() ) {
01325 personString += htmlAddUidLink( email, printName, printUid );
01326 } else {
01327
01328 personString += ( printName.isEmpty() ? email : printName );
01329 }
01330 personString += '\n';
01331
01332
01333 if ( !email.isEmpty() ) {
01334 personString += " " + htmlAddMailtoLink( email, printName );
01335 }
01336 personString += "\n";
01337
01338 return personString;
01339 }
01340
01341 static QString invitationDetailsIncidence( Incidence *incidence, bool noHtmlMode )
01342 {
01343
01344
01345
01346
01347 QString html;
01348 QString descr;
01349 QStringList comments;
01350
01351 if ( incidence->comments().isEmpty() ) {
01352 if ( !incidence->description().isEmpty() ) {
01353
01354 if ( !QStyleSheet::mightBeRichText( incidence->description() ) ) {
01355 comments << string2HTML( incidence->description() );
01356 } else {
01357 comments << incidence->description();
01358 if ( noHtmlMode ) {
01359 comments[0] = cleanHtml( comments[0] );
01360 }
01361 comments[0] = htmlAddTag( "p", comments[0] );
01362 }
01363 }
01364
01365 } else {
01366
01367 QStringList cl = incidence->comments();
01368 uint i = 0;
01369 for( QStringList::Iterator it=cl.begin(); it!=cl.end(); ++it ) {
01370 if ( !QStyleSheet::mightBeRichText( *it ) ) {
01371 comments.append( string2HTML( *it ) );
01372 } else {
01373 if ( noHtmlMode ) {
01374 comments.append( cleanHtml( "<body>" + (*it) + "</body>" ) );
01375 } else {
01376 comments.append( *it );
01377 }
01378 }
01379 i++;
01380 }
01381 if ( !incidence->description().isEmpty() ) {
01382
01383 if ( !QStyleSheet::mightBeRichText( incidence->description() ) ) {
01384 descr = string2HTML( incidence->description() );
01385 } else {
01386 descr = incidence->description();
01387 if ( noHtmlMode ) {
01388 descr = cleanHtml( descr );
01389 }
01390 descr = htmlAddTag( "p", descr );
01391 }
01392 }
01393 }
01394
01395 if( !descr.isEmpty() ) {
01396 html += "<p>";
01397 html += "<table border=\"0\" style=\"margin-top:4px;\">";
01398 html += "<tr><td><center>" +
01399 htmlAddTag( "u", i18n( "Description:" ) ) +
01400 "</center></td></tr>";
01401 html += "<tr><td>" + descr + "</td></tr>";
01402 html += "</table>";
01403 }
01404
01405 if ( !comments.isEmpty() ) {
01406 html += "<p>";
01407 html += "<table border=\"0\" style=\"margin-top:4px;\">";
01408 html += "<tr><td><center>" +
01409 htmlAddTag( "u", i18n( "Comments:" ) ) +
01410 "</center></td></tr>";
01411 html += "<tr><td>";
01412 if ( comments.count() > 1 ) {
01413 html += "<ul>";
01414 for ( uint i=0; i < comments.count(); ++i ) {
01415 html += "<li>" + comments[i] + "</li>";
01416 }
01417 html += "</ul>";
01418 } else {
01419 html += comments[0];
01420 }
01421 html += "</td></tr>";
01422 html += "</table>";
01423 }
01424 return html;
01425 }
01426
01427 static QString invitationDetailsEvent( Event* event, bool noHtmlMode )
01428 {
01429
01430 if ( !event ) {
01431 return QString::null;
01432 }
01433
01434 QString html = htmlInvitationDetailsBegin();
01435 html += htmlInvitationDetailsTableBegin();
01436
01437
01438 html += htmlRow( i18n( "What:" ), invitationSummary( event, noHtmlMode ) );
01439 html += htmlRow( i18n( "Where:" ), invitationLocation( event, noHtmlMode ) );
01440
01441
01442 if ( event->dtStart().date() == event->dtEnd().date() ) {
01443 html += htmlRow( i18n( "Date:" ),
01444 IncidenceFormatter::dateToString( event->dtStart(), false ) );
01445 if ( !event->doesFloat() ) {
01446 html += htmlRow( i18n( "Time:" ),
01447 IncidenceFormatter::timeToString( event->dtStart(), true ) +
01448 " - " +
01449 IncidenceFormatter::timeToString( event->dtEnd(), true ) );
01450 }
01451 } else {
01452 html += htmlRow( i18n( "Starting date of an event", "From:" ),
01453 IncidenceFormatter::dateToString( event->dtStart(), false ) );
01454 if ( !event->doesFloat() ) {
01455 html += htmlRow( i18n( "Starting time of an event", "At:" ),
01456 IncidenceFormatter::timeToString( event->dtStart(), true ) );
01457 }
01458 if ( event->hasEndDate() ) {
01459 html += htmlRow( i18n( "Ending date of an event", "To:" ),
01460 IncidenceFormatter::dateToString( event->dtEnd(), false ) );
01461 if ( !event->doesFloat() ) {
01462 html += htmlRow( i18n( "Starting time of an event", "At:" ),
01463 IncidenceFormatter::timeToString( event->dtEnd(), true ) );
01464 }
01465 } else {
01466 html += htmlRow( i18n( "Ending date of an event", "To:" ),
01467 i18n( "no end date specified" ) );
01468 }
01469 }
01470
01471
01472 html += htmlRow( i18n( "Duration:" ), IncidenceFormatter::durationString( event ) );
01473
01474
01475 if ( event->doesRecur() ) {
01476 html += htmlRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( event ) );
01477 }
01478
01479 html += htmlInvitationDetailsTableEnd();
01480 html += invitationDetailsIncidence( event, noHtmlMode );
01481 html += htmlInvitationDetailsEnd();
01482
01483 return html;
01484 }
01485
01486 static QString invitationDetailsEvent( Event *event, Event *oldevent, bool noHtmlMode )
01487 {
01488 if ( !oldevent ) {
01489 return invitationDetailsEvent( event, noHtmlMode );
01490 }
01491
01492 QString html = htmlInvitationDetailsBegin();
01493 html += htmlInvitationDetailsTableBegin();
01494
01495 html += htmlRow( i18n( "What:" ),
01496 invitationSummary( event, noHtmlMode ),
01497 invitationSummary( oldevent, noHtmlMode ) );
01498
01499 html += htmlRow( i18n( "Where:" ),
01500 invitationLocation( event, noHtmlMode ),
01501 invitationLocation( oldevent, noHtmlMode ) );
01502
01503
01504
01505 if ( event->dtStart().date() == event->dtEnd().date() ) {
01506 html += htmlRow( i18n( "Date:" ),
01507 IncidenceFormatter::dateToString( event->dtStart(), false ),
01508 IncidenceFormatter::dateToString( oldevent->dtStart(), false ) );
01509 QString spanStr , oldspanStr;
01510 if ( !event->doesFloat() ) {
01511 spanStr = IncidenceFormatter::timeToString( event->dtStart(), true ) +
01512 " - " +
01513 IncidenceFormatter::timeToString( event->dtEnd(), true );
01514 }
01515 if ( !oldevent->doesFloat() ) {
01516 oldspanStr = IncidenceFormatter::timeToString( oldevent->dtStart(), true ) +
01517 " - " +
01518 IncidenceFormatter::timeToString( oldevent->dtEnd(), true );
01519 }
01520 html += htmlRow( i18n( "Time:" ), spanStr, oldspanStr );
01521 } else {
01522 html += htmlRow( i18n( "Starting date of an event", "From:" ),
01523 IncidenceFormatter::dateToString( event->dtStart(), false ),
01524 IncidenceFormatter::dateToString( oldevent->dtStart(), false ) );
01525 QString startStr, oldstartStr;
01526 if ( !event->doesFloat() ) {
01527 startStr = IncidenceFormatter::timeToString( event->dtStart(), true );
01528 }
01529 if ( !oldevent->doesFloat() ) {
01530 oldstartStr = IncidenceFormatter::timeToString( oldevent->dtStart(), true );
01531 }
01532 html += htmlRow( i18n( "Starting time of an event", "At:" ), startStr, oldstartStr );
01533
01534 if ( event->hasEndDate() ) {
01535 html += htmlRow( i18n( "Ending date of an event", "To:" ),
01536 IncidenceFormatter::dateToString( event->dtEnd(), false ),
01537 IncidenceFormatter::dateToString( oldevent->dtEnd(), false ) );
01538 QString endStr, oldendStr;
01539 if ( !event->doesFloat() ) {
01540 endStr = IncidenceFormatter::timeToString( event->dtEnd(), true );
01541 }
01542 if ( !oldevent->doesFloat() ) {
01543 oldendStr = IncidenceFormatter::timeToString( oldevent->dtEnd(), true );
01544 }
01545 html += htmlRow( i18n( "Starting time of an event", "At:" ), endStr, oldendStr );
01546 } else {
01547 QString endStr = i18n( "no end date specified" );
01548 QString oldendStr;
01549 if ( !oldevent->hasEndDate() ) {
01550 oldendStr = i18n( "no end date specified" );
01551 } else {
01552 oldendStr = IncidenceFormatter::dateTimeToString( oldevent->dtEnd(),
01553 oldevent->doesFloat(), false );
01554 }
01555 html += htmlRow( i18n( "Ending date of an event", "To:" ), endStr, oldendStr );
01556 }
01557 }
01558
01559 html += htmlRow( i18n( "Duration:" ),
01560 IncidenceFormatter::durationString( event ),
01561 IncidenceFormatter::durationString( oldevent ) );
01562
01563 QString recurStr, oldrecurStr;
01564 if ( event->doesRecur() ) {
01565 recurStr = IncidenceFormatter::recurrenceString( event );
01566 }
01567 if ( oldevent->doesRecur() ) {
01568 oldrecurStr = IncidenceFormatter::recurrenceString( oldevent );
01569 }
01570 html += htmlRow( i18n( "Recurrence:" ), recurStr, oldrecurStr );
01571
01572 html += htmlInvitationDetailsTableEnd();
01573 html += invitationDetailsIncidence( event, noHtmlMode );
01574 html += htmlInvitationDetailsEnd();
01575
01576 return html;
01577 }
01578
01579 static QString invitationDetailsTodo( Todo *todo, bool noHtmlMode )
01580 {
01581
01582 if ( !todo ) {
01583 return QString::null;
01584 }
01585
01586 QString html = htmlInvitationDetailsBegin();
01587 html += htmlInvitationDetailsTableBegin();
01588
01589
01590 html += htmlRow( i18n( "What:" ), invitationSummary( todo, noHtmlMode ) );
01591 html += htmlRow( i18n( "Where:" ), invitationLocation( todo, noHtmlMode ) );
01592
01593 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
01594 html += htmlRow( i18n( "Start Date:" ),
01595 IncidenceFormatter::dateToString( todo->dtStart(), false ) );
01596 if ( !todo->doesFloat() ) {
01597 html += htmlRow( i18n( "Start Time:" ),
01598 IncidenceFormatter::timeToString( todo->dtStart(), false ) );
01599 }
01600 }
01601 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
01602 html += htmlRow( i18n( "Due Date:" ),
01603 IncidenceFormatter::dateToString( todo->dtDue(), false ) );
01604 if ( !todo->doesFloat() ) {
01605 html += htmlRow( i18n( "Due Time:" ),
01606 IncidenceFormatter::timeToString( todo->dtDue(), false ) );
01607 }
01608 } else {
01609 html += htmlRow( i18n( "Due Date:" ), i18n( "Due Date: None", "None" ) );
01610 }
01611
01612
01613 html += htmlRow( i18n( "Duration:" ), IncidenceFormatter::durationString( todo ) );
01614
01615
01616 if ( todo->doesRecur() ) {
01617 html += htmlRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( todo ) );
01618 }
01619
01620 html += htmlInvitationDetailsTableEnd();
01621 html += invitationDetailsIncidence( todo, noHtmlMode );
01622 html += htmlInvitationDetailsEnd();
01623
01624 return html;
01625 }
01626
01627 static QString invitationDetailsTodo( Todo *todo, Todo *oldtodo, bool noHtmlMode )
01628 {
01629 if ( !oldtodo ) {
01630 return invitationDetailsTodo( todo, noHtmlMode );
01631 }
01632
01633 QString html = htmlInvitationDetailsBegin();
01634 html += htmlInvitationDetailsTableBegin();
01635
01636 html += htmlRow( i18n( "What:" ),
01637 invitationSummary( todo, noHtmlMode ),
01638 invitationSummary( todo, noHtmlMode ) );
01639
01640 html += htmlRow( i18n( "Where:" ),
01641 invitationLocation( todo, noHtmlMode ),
01642 invitationLocation( oldtodo, noHtmlMode ) );
01643
01644 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
01645 html += htmlRow( i18n( "Start Date:" ),
01646 IncidenceFormatter::dateToString( todo->dtStart(), false ),
01647 IncidenceFormatter::dateToString( oldtodo->dtStart(), false ) );
01648 QString startTimeStr, oldstartTimeStr;
01649 if ( !todo->doesFloat() ) {
01650 startTimeStr = IncidenceFormatter::timeToString( todo->dtStart(), false );
01651 }
01652 if ( !oldtodo->doesFloat() ) {
01653 oldstartTimeStr = IncidenceFormatter::timeToString( oldtodo->dtStart(), false );
01654 }
01655 html += htmlRow( i18n( "Start Time:" ), startTimeStr, oldstartTimeStr );
01656 }
01657
01658 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
01659 html += htmlRow( i18n( "Due Date:" ),
01660 IncidenceFormatter::dateToString( todo->dtDue(), false ),
01661 IncidenceFormatter::dateToString( oldtodo->dtDue(), false ) );
01662 QString endTimeStr, oldendTimeStr;
01663 if ( !todo->doesFloat() ) {
01664 endTimeStr = IncidenceFormatter::timeToString( todo->dtDue(), false );
01665 }
01666 if ( !oldtodo->doesFloat() ) {
01667 oldendTimeStr = IncidenceFormatter::timeToString( oldtodo->dtDue(), false );
01668 }
01669 html += htmlRow( i18n( "Due Time:" ), endTimeStr, oldendTimeStr );
01670 } else {
01671 QString dueStr = i18n( "Due Date: None", "None" );
01672 QString olddueStr;
01673 if ( !oldtodo->hasDueDate() || !oldtodo->dtDue().isValid() ) {
01674 olddueStr = i18n( "Due Date: None", "None" );
01675 } else {
01676 olddueStr = IncidenceFormatter::dateTimeToString( oldtodo->dtDue(),
01677 oldtodo->doesFloat(), false );
01678 }
01679 html += htmlRow( i18n( "Due Date:" ), dueStr, olddueStr );
01680 }
01681
01682 html += htmlRow( i18n( "Duration:" ),
01683 IncidenceFormatter::durationString( todo ),
01684 IncidenceFormatter::durationString( oldtodo ) );
01685
01686 QString recurStr, oldrecurStr;
01687 if ( todo->doesRecur() ) {
01688 recurStr = IncidenceFormatter::recurrenceString( todo );
01689 }
01690 if ( oldtodo->doesRecur() ) {
01691 oldrecurStr = IncidenceFormatter::recurrenceString( oldtodo );
01692 }
01693 html += htmlRow( i18n( "Recurrence:" ), recurStr, oldrecurStr );
01694
01695 html += htmlInvitationDetailsTableEnd();
01696 html += invitationDetailsIncidence( todo, noHtmlMode );
01697 html += htmlInvitationDetailsEnd();
01698
01699 return html;
01700 }
01701
01702 static QString invitationDetailsJournal( Journal *journal, bool noHtmlMode )
01703 {
01704 if ( !journal ) {
01705 return QString::null;
01706 }
01707
01708 QString html = htmlInvitationDetailsBegin();
01709 html += htmlInvitationDetailsTableBegin();
01710
01711 html += htmlRow( i18n( "Summary:" ), invitationSummary( journal, noHtmlMode ) );
01712 html += htmlRow( i18n( "Date:" ), IncidenceFormatter::dateToString( journal->dtStart(), false ) );
01713
01714 html += htmlInvitationDetailsTableEnd();
01715 html += invitationDetailsIncidence( journal, noHtmlMode );
01716 html += htmlInvitationDetailsEnd();
01717
01718 return html;
01719 }
01720
01721 static QString invitationDetailsJournal( Journal *journal, Journal *oldjournal, bool noHtmlMode )
01722 {
01723 if ( !oldjournal ) {
01724 return invitationDetailsJournal( journal, noHtmlMode );
01725 }
01726
01727 QString html = htmlInvitationDetailsBegin();
01728 html += htmlInvitationDetailsTableBegin();
01729
01730 html += htmlRow( i18n( "What:" ),
01731 invitationSummary( journal, noHtmlMode ),
01732 invitationSummary( oldjournal, noHtmlMode ) );
01733
01734 html += htmlRow( i18n( "Date:" ),
01735 IncidenceFormatter::dateToString( journal->dtStart(), false ),
01736 IncidenceFormatter::dateToString( oldjournal->dtStart(), false ) );
01737
01738 html += htmlInvitationDetailsTableEnd();
01739 html += invitationDetailsIncidence( journal, noHtmlMode );
01740 html += htmlInvitationDetailsEnd();
01741
01742 return html;
01743 }
01744
01745 static QString invitationDetailsFreeBusy( FreeBusy *fb, bool )
01746 {
01747 if ( !fb ) {
01748 return QString::null;
01749 }
01750
01751 QString html = htmlInvitationDetailsTableBegin();
01752
01753 html += htmlRow( i18n("Person:"), fb->organizer().fullName() );
01754 html += htmlRow( i18n("Start date:"),
01755 IncidenceFormatter::dateToString( fb->dtStart(), true ) );
01756 html += htmlRow( i18n("End date:"),
01757 KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
01758 html += "<tr><td colspan=2><hr></td></tr>\n";
01759 html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
01760
01761 QValueList<Period> periods = fb->busyPeriods();
01762
01763 QValueList<Period>::iterator it;
01764 for ( it = periods.begin(); it != periods.end(); ++it ) {
01765 Period per = *it;
01766 if ( per.hasDuration() ) {
01767 int dur = per.duration().asSeconds();
01768 QString cont;
01769 if ( dur >= 3600 ) {
01770 cont += i18n("1 hour ", "%n hours ", dur / 3600);
01771 dur %= 3600;
01772 }
01773 if ( dur >= 60 ) {
01774 cont += i18n("1 minute", "%n minutes ", dur / 60);
01775 dur %= 60;
01776 }
01777 if ( dur > 0 ) {
01778 cont += i18n("1 second", "%n seconds", dur);
01779 }
01780 html += htmlRow( QString::null, i18n("startDate for duration", "%1 for %2").
01781 arg( KGlobal::locale()->formatDateTime( per.start(), false ) ).
01782 arg(cont) );
01783 } else {
01784 QString cont;
01785 if ( per.start().date() == per.end().date() ) {
01786 cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
01787 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
01788 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
01789 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
01790 } else {
01791 cont = i18n("fromDateTime - toDateTime", "%1 - %2")
01792 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
01793 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
01794 }
01795
01796 html += htmlRow( QString::null, cont );
01797 }
01798 }
01799
01800 html += htmlInvitationDetailsTableEnd();
01801 return html;
01802 }
01803
01804 static QString invitationDetailsFreeBusy( FreeBusy *freebusy, FreeBusy *oldfreebusy, bool noHtmlMode )
01805 {
01806 Q_UNUSED( oldfreebusy );
01807 return invitationDetailsFreeBusy( freebusy, noHtmlMode );
01808 }
01809
01810 static bool replyMeansCounter( Incidence * )
01811 {
01812 return false;
01827 }
01828
01829 static QString invitationHeaderEvent( Event *event, Incidence *existingIncidence,
01830 ScheduleMessage *msg, const QString &sender )
01831 {
01832 if ( !msg || !event )
01833 return QString::null;
01834
01835 switch ( msg->method() ) {
01836 case Scheduler::Publish:
01837 return i18n( "This invitation has been published" );
01838 case Scheduler::Request:
01839 if ( existingIncidence && event->revision() > 0 ) {
01840 return i18n( "This invitation has been updated by the organizer %1" ).
01841 arg( event->organizer().fullName() );
01842 }
01843 if ( iamOrganizer( event ) ) {
01844 return i18n( "I created this invitation" );
01845 } else {
01846 QString orgStr;
01847 if ( !event->organizer().fullName().isEmpty() ) {
01848 orgStr = event->organizer().fullName();
01849 } else if ( !event->organizer().email().isEmpty() ) {
01850 orgStr = event->organizer().email();
01851 }
01852 if ( senderIsOrganizer( event, sender ) ) {
01853 if ( !orgStr.isEmpty() ) {
01854 return i18n( "You received an invitation from %1" ).arg( orgStr );
01855 } else {
01856 return i18n( "You received an invitation" );
01857 }
01858 } else {
01859 if ( !orgStr.isEmpty() ) {
01860 return i18n( "You received an invitation from %1 as a representative of %2" ).
01861 arg( sender, orgStr );
01862 } else {
01863 return i18n( "You received an invitation from %1 as the organizer's representative" ).
01864 arg( sender );
01865 }
01866 }
01867 }
01868 case Scheduler::Refresh:
01869 return i18n( "This invitation was refreshed" );
01870 case Scheduler::Cancel:
01871 if ( iamOrganizer( event ) ) {
01872 return i18n( "This invitation has been canceled" );
01873 } else {
01874 return i18n( "The organizer has removed you from the invitation" );
01875 }
01876 case Scheduler::Add:
01877 return i18n( "Addition to the invitation" );
01878 case Scheduler::Reply:
01879 {
01880 if ( replyMeansCounter( event ) ) {
01881 return i18n( "%1 makes this counter proposal" ).
01882 arg( firstAttendeeName( event, i18n( "Sender" ) ) );
01883 }
01884
01885 Attendee::List attendees = event->attendees();
01886 if( attendees.count() == 0 ) {
01887 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01888 return QString::null;
01889 }
01890 if( attendees.count() != 1 ) {
01891 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01892 << "but is " << attendees.count() << endl;
01893 }
01894 QString attendeeName = firstAttendeeName( event, i18n( "Sender" ) );
01895
01896 QString delegatorName, dummy;
01897 Attendee* attendee = *attendees.begin();
01898 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
01899 if ( delegatorName.isEmpty() ) {
01900 delegatorName = attendee->delegator();
01901 }
01902
01903 switch( attendee->status() ) {
01904 case Attendee::NeedsAction:
01905 return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
01906 case Attendee::Accepted:
01907 if ( event->revision() > 0 ) {
01908 if ( !sender.isEmpty() ) {
01909 return i18n( "This invitation has been updated by attendee %1" ).arg( sender );
01910 } else {
01911 return i18n( "This invitation has been updated by an attendee" );
01912 }
01913 } else {
01914 if ( delegatorName.isEmpty() ) {
01915 return i18n( "%1 accepts this invitation" ).arg( attendeeName );
01916 } else {
01917 return i18n( "%1 accepts this invitation on behalf of %2" ).
01918 arg( attendeeName ).arg( delegatorName );
01919 }
01920 }
01921 case Attendee::Tentative:
01922 if ( delegatorName.isEmpty() ) {
01923 return i18n( "%1 tentatively accepts this invitation" ).
01924 arg( attendeeName );
01925 } else {
01926 return i18n( "%1 tentatively accepts this invitation on behalf of %2" ).
01927 arg( attendeeName ).arg( delegatorName );
01928 }
01929 case Attendee::Declined:
01930 if ( delegatorName.isEmpty() ) {
01931 return i18n( "%1 declines this invitation" ).arg( attendeeName );
01932 } else {
01933 return i18n( "%1 declines this invitation on behalf of %2" ).
01934 arg( attendeeName ).arg( delegatorName );
01935 }
01936 case Attendee::Delegated: {
01937 QString delegate, dummy;
01938 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
01939 if ( delegate.isEmpty() ) {
01940 delegate = attendee->delegate();
01941 }
01942 if ( !delegate.isEmpty() ) {
01943 return i18n( "%1 has delegated this invitation to %2" ).
01944 arg( attendeeName ) .arg( delegate );
01945 } else {
01946 return i18n( "%1 has delegated this invitation" ).arg( attendeeName );
01947 }
01948 }
01949 case Attendee::Completed:
01950 return i18n( "This invitation is now completed" );
01951 case Attendee::InProcess:
01952 return i18n( "%1 is still processing the invitation" ).
01953 arg( attendeeName );
01954 default:
01955 return i18n( "Unknown response to this invitation" );
01956 }
01957 break;
01958 }
01959
01960 case Scheduler::Counter:
01961 return i18n( "%1 makes this counter proposal" ).
01962 arg( firstAttendeeName( event, i18n( "Sender" ) ) );
01963
01964 case Scheduler::Declinecounter:
01965 return i18n( "%1 declines the counter proposal" ).
01966 arg( firstAttendeeName( event, i18n( "Sender" ) ) );
01967
01968 case Scheduler::NoMethod:
01969 return i18n("Error: iMIP message with unknown method: '%1'").
01970 arg( msg->method() );
01971 }
01972 return QString::null;
01973 }
01974
01975 static QString invitationHeaderTodo( Todo *todo, Incidence *existingIncidence,
01976 ScheduleMessage *msg, const QString &sender )
01977 {
01978 if ( !msg || !todo ) {
01979 return QString::null;
01980 }
01981
01982 switch ( msg->method() ) {
01983 case Scheduler::Publish:
01984 return i18n("This task has been published");
01985 case Scheduler::Request:
01986 if ( existingIncidence && todo->revision() > 0 ) {
01987 return i18n( "This task has been updated by the organizer %1" ).
01988 arg( todo->organizer().fullName() );
01989 } else {
01990 if ( iamOrganizer( todo ) ) {
01991 return i18n( "I created this task" );
01992 } else {
01993 QString orgStr;
01994 if ( !todo->organizer().fullName().isEmpty() ) {
01995 orgStr = todo->organizer().fullName();
01996 } else if ( !todo->organizer().email().isEmpty() ) {
01997 orgStr = todo->organizer().email();
01998 }
01999 if ( senderIsOrganizer( todo, sender ) ) {
02000 if ( !orgStr.isEmpty() ) {
02001 return i18n( "You have been assigned this task by %1" ).arg( orgStr );
02002 } else {
02003 return i18n( "You have been assigned this task" );
02004 }
02005 } else {
02006 if ( !orgStr.isEmpty() ) {
02007 return i18n( "You have been assigned this task by %1 as a representative of %2" ).
02008 arg( sender, orgStr );
02009 } else {
02010 return i18n( "You have been assigned this task by %1 as the organizer's representative" ).
02011 arg( sender );
02012 }
02013 }
02014 }
02015 }
02016 case Scheduler::Refresh:
02017 return i18n( "This task was refreshed" );
02018 case Scheduler::Cancel:
02019 if ( iamOrganizer( todo ) ) {
02020 return i18n( "This task was canceled" );
02021 } else {
02022 return i18n( "The organizer has removed you from this task" );
02023 }
02024 case Scheduler::Add:
02025 return i18n( "Addition to the task" );
02026 case Scheduler::Reply:
02027 {
02028 if ( replyMeansCounter( todo ) ) {
02029 return i18n( "%1 makes this counter proposal" ).
02030 arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
02031 }
02032
02033 Attendee::List attendees = todo->attendees();
02034 if( attendees.count() == 0 ) {
02035 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
02036 return QString::null;
02037 }
02038 if( attendees.count() != 1 ) {
02039 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
02040 << "but is " << attendees.count() << endl;
02041 }
02042 QString attendeeName = firstAttendeeName( todo, i18n( "Sender" ) );
02043
02044 QString delegatorName, dummy;
02045 Attendee* attendee = *attendees.begin();
02046 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
02047 if ( delegatorName.isEmpty() ) {
02048 delegatorName = attendee->delegator();
02049 }
02050
02051 switch( attendee->status() ) {
02052 case Attendee::NeedsAction:
02053 return i18n( "%1 indicates this task assignment still needs some action" ).arg( attendeeName );
02054 case Attendee::Accepted:
02055 if ( todo->revision() > 0 ) {
02056 if ( !sender.isEmpty() ) {
02057 if ( todo->isCompleted() ) {
02058 return i18n( "This task has been completed by assignee %1" ).arg( sender );
02059 } else {
02060 return i18n( "This task has been updated by assignee %1" ).arg( sender );
02061 }
02062 } else {
02063 if ( todo->isCompleted() ) {
02064 return i18n( "This task has been completed by an assignee" );
02065 } else {
02066 return i18n( "This task has been updated by an assignee" );
02067 }
02068 }
02069 } else {
02070 if ( delegatorName.isEmpty() ) {
02071 return i18n( "%1 accepts this task" ).arg( attendeeName );
02072 } else {
02073 return i18n( "%1 accepts this task on behalf of %2" ).
02074 arg( attendeeName ).arg( delegatorName );
02075 }
02076 }
02077 case Attendee::Tentative:
02078 if ( delegatorName.isEmpty() ) {
02079 return i18n( "%1 tentatively accepts this task" ).
02080 arg( attendeeName );
02081 } else {
02082 return i18n( "%1 tentatively accepts this task on behalf of %2" ).
02083 arg( attendeeName ).arg( delegatorName );
02084 }
02085 case Attendee::Declined:
02086 if ( delegatorName.isEmpty() ) {
02087 return i18n( "%1 declines this task" ).arg( attendeeName );
02088 } else {
02089 return i18n( "%1 declines this task on behalf of %2" ).
02090 arg( attendeeName ).arg( delegatorName );
02091 }
02092 case Attendee::Delegated: {
02093 QString delegate, dummy;
02094 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
02095 if ( delegate.isEmpty() ) {
02096 delegate = attendee->delegate();
02097 }
02098 if ( !delegate.isEmpty() ) {
02099 return i18n( "%1 has delegated this request for the task to %2" ).
02100 arg( attendeeName ).arg( delegate );
02101 } else {
02102 return i18n( "%1 has delegated this request for the task" ).
02103 arg( attendeeName );
02104 }
02105 }
02106 case Attendee::Completed:
02107 return i18n( "The request for this task is now completed" );
02108 case Attendee::InProcess:
02109 return i18n( "%1 is still processing the task" ).
02110 arg( attendeeName );
02111 default:
02112 return i18n( "Unknown response to this task" );
02113 }
02114 break;
02115 }
02116
02117 case Scheduler::Counter:
02118 return i18n( "%1 makes this counter proposal" ).
02119 arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
02120
02121 case Scheduler::Declinecounter:
02122 return i18n( "%1 declines the counter proposal" ).
02123 arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
02124
02125 case Scheduler::NoMethod:
02126 return i18n( "Error: iMIP message with unknown method: '%1'" ).
02127 arg( msg->method() );
02128 }
02129 return QString::null;
02130 }
02131
02132 static QString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
02133 {
02134 if ( !msg || !journal ) {
02135 return QString::null;
02136 }
02137
02138 switch ( msg->method() ) {
02139 case Scheduler::Publish:
02140 return i18n("This journal has been published");
02141 case Scheduler::Request:
02142 return i18n( "You have been assigned this journal" );
02143 case Scheduler::Refresh:
02144 return i18n( "This journal was refreshed" );
02145 case Scheduler::Cancel:
02146 return i18n( "This journal was canceled" );
02147 case Scheduler::Add:
02148 return i18n( "Addition to the journal" );
02149 case Scheduler::Reply:
02150 {
02151 if ( replyMeansCounter( journal ) ) {
02152 return i18n( "Sender makes this counter proposal" );
02153 }
02154
02155 Attendee::List attendees = journal->attendees();
02156 if( attendees.count() == 0 ) {
02157 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
02158 return QString::null;
02159 }
02160 if( attendees.count() != 1 ) {
02161 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
02162 << "but is " << attendees.count() << endl;
02163 }
02164 Attendee* attendee = *attendees.begin();
02165
02166 switch( attendee->status() ) {
02167 case Attendee::NeedsAction:
02168 return i18n( "Sender indicates this journal assignment still needs some action" );
02169 case Attendee::Accepted:
02170 return i18n( "Sender accepts this journal" );
02171 case Attendee::Tentative:
02172 return i18n( "Sender tentatively accepts this journal" );
02173 case Attendee::Declined:
02174 return i18n( "Sender declines this journal" );
02175 case Attendee::Delegated:
02176 return i18n( "Sender has delegated this request for the journal" );
02177 case Attendee::Completed:
02178 return i18n( "The request for this journal is now completed" );
02179 case Attendee::InProcess:
02180 return i18n( "Sender is still processing the invitation" );
02181 default:
02182 return i18n( "Unknown response to this journal" );
02183 }
02184 break;
02185 }
02186 case Scheduler::Counter:
02187 return i18n( "Sender makes this counter proposal" );
02188 case Scheduler::Declinecounter:
02189 return i18n( "Sender declines the counter proposal" );
02190 case Scheduler::NoMethod:
02191 return i18n("Error: iMIP message with unknown method: '%1'").
02192 arg( msg->method() );
02193 }
02194 return QString::null;
02195 }
02196
02197 static QString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
02198 {
02199 if ( !msg || !fb ) {
02200 return QString::null;
02201 }
02202
02203 switch ( msg->method() ) {
02204 case Scheduler::Publish:
02205 return i18n("This free/busy list has been published");
02206 case Scheduler::Request:
02207 return i18n( "The free/busy list has been requested" );
02208 case Scheduler::Refresh:
02209 return i18n( "This free/busy list was refreshed" );
02210 case Scheduler::Cancel:
02211 return i18n( "This free/busy list was canceled" );
02212 case Scheduler::Add:
02213 return i18n( "Addition to the free/busy list" );
02214 case Scheduler::NoMethod:
02215 default:
02216 return i18n("Error: Free/Busy iMIP message with unknown method: '%1'").
02217 arg( msg->method() );
02218 }
02219 }
02220
02221 static QString invitationAttendeeList( Incidence *incidence )
02222 {
02223 QString tmpStr;
02224 if ( !incidence ) {
02225 return tmpStr;
02226 }
02227
02228 if ( incidence->type() == "Todo" ) {
02229 tmpStr += htmlAddTag( "u", i18n( "Assignees" ) );
02230 } else {
02231 tmpStr += htmlAddTag( "u", i18n( "Invitation List" ) );
02232 }
02233 tmpStr += "<br/>";
02234
02235 int count=0;
02236 Attendee::List attendees = incidence->attendees();
02237 if ( !attendees.isEmpty() ) {
02238
02239 Attendee::List::ConstIterator it;
02240 for( it = attendees.begin(); it != attendees.end(); ++it ) {
02241 Attendee *a = *it;
02242 if ( !iamAttendee( a ) && !attendeeIsOrganizer( incidence, a ) ) {
02243 count++;
02244 if ( count == 1 ) {
02245 tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"1\">";
02246 }
02247 tmpStr += "<tr>";
02248 tmpStr += "<td>";
02249 tmpStr += invitationPerson( a->email(), a->name(), QString::null );
02250 if ( !a->delegator().isEmpty() ) {
02251 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
02252 }
02253 if ( !a->delegate().isEmpty() ) {
02254 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
02255 }
02256 tmpStr += "</td>";
02257 tmpStr += "</tr>";
02258 }
02259 }
02260 }
02261 if ( count ) {
02262 tmpStr += "</table>";
02263 } else {
02264 tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
02265 }
02266
02267 return tmpStr;
02268 }
02269
02270 static QString invitationRsvpList( Incidence *incidence, Attendee *sender )
02271 {
02272 QString tmpStr;
02273 if ( !incidence ) {
02274 return tmpStr;
02275 }
02276
02277 if ( incidence->type() == "Todo" ) {
02278 tmpStr += htmlAddTag( "u", i18n( "Assignees" ) );
02279 } else {
02280 tmpStr += htmlAddTag( "u", i18n( "Invitation List" ) );
02281 }
02282 tmpStr += "<br/>";
02283
02284 int count=0;
02285 Attendee::List attendees = incidence->attendees();
02286 if ( !attendees.isEmpty() ) {
02287
02288 Attendee::List::ConstIterator it;
02289 for( it = attendees.begin(); it != attendees.end(); ++it ) {
02290 Attendee *a = *it;
02291 if ( !iamAttendee( a ) && !attendeeIsOrganizer( incidence, a ) ) {
02292 QString statusStr = a->statusStr();
02293 if ( sender && a->email() == sender->email() ) {
02294
02295
02296 if ( a->status() != sender->status() ) {
02297 statusStr = i18n( "%1 (<i>unrecorded</i>)" ).arg( sender->statusStr() );
02298 }
02299 a = sender;
02300 }
02301 count++;
02302 if ( count == 1 ) {
02303 tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"2\">";
02304 }
02305 tmpStr += "<tr>";
02306 tmpStr += "<td>";
02307 tmpStr += invitationPerson( a->email(), a->name(), QString::null );
02308 if ( !a->delegator().isEmpty() ) {
02309 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
02310 }
02311 if ( !a->delegate().isEmpty() ) {
02312 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
02313 }
02314 tmpStr += "</td>";
02315 tmpStr += "<td>" + statusStr + "</td>";
02316 tmpStr += "</tr>";
02317 }
02318 }
02319 }
02320 if ( count ) {
02321 tmpStr += "</table>";
02322 } else {
02323 tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
02324 }
02325
02326 return tmpStr;
02327 }
02328
02329 static QString invitationAttachments( InvitationFormatterHelper *helper, Incidence *incidence )
02330 {
02331 QString tmpStr;
02332 if ( !incidence ) {
02333 return tmpStr;
02334 }
02335
02336 Attachment::List attachments = incidence->attachments();
02337 if ( !attachments.isEmpty() ) {
02338 tmpStr += i18n( "Attached Documents:" ) + "<ol>";
02339
02340 Attachment::List::ConstIterator it;
02341 for( it = attachments.begin(); it != attachments.end(); ++it ) {
02342 Attachment *a = *it;
02343 tmpStr += "<li>";
02344
02345 KMimeType::Ptr mimeType = KMimeType::mimeType( a->mimeType() );
02346 const QString iconStr = mimeType ? mimeType->icon( a->uri(), false ) : QString( "application-octet-stream" );
02347 const QString iconPath = KGlobal::iconLoader()->iconPath( iconStr, KIcon::Small );
02348 if ( !iconPath.isEmpty() ) {
02349 tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
02350 }
02351 tmpStr += helper->makeLink( "ATTACH:" + a->label(), a->label() );
02352 tmpStr += "</li>";
02353 }
02354 tmpStr += "</ol>";
02355 }
02356
02357 return tmpStr;
02358 }
02359
02360 class IncidenceFormatter::ScheduleMessageVisitor
02361 : public IncidenceBase::Visitor
02362 {
02363 public:
02364 ScheduleMessageVisitor() : mExistingIncidence( 0 ), mMessage( 0 ) { mResult = ""; }
02365 bool act( IncidenceBase *incidence, Incidence *existingIncidence, ScheduleMessage *msg,
02366 const QString &sender )
02367 {
02368 mExistingIncidence = existingIncidence;
02369 mMessage = msg;
02370 mSender = sender;
02371 return incidence->accept( *this );
02372 }
02373 QString result() const { return mResult; }
02374
02375 protected:
02376 QString mResult;
02377 Incidence *mExistingIncidence;
02378 ScheduleMessage *mMessage;
02379 QString mSender;
02380 };
02381
02382 class IncidenceFormatter::InvitationHeaderVisitor
02383 : public IncidenceFormatter::ScheduleMessageVisitor
02384 {
02385 protected:
02386 bool visit( Event *event )
02387 {
02388 mResult = invitationHeaderEvent( event, mExistingIncidence, mMessage, mSender );
02389 return !mResult.isEmpty();
02390 }
02391 bool visit( Todo *todo )
02392 {
02393 mResult = invitationHeaderTodo( todo, mExistingIncidence, mMessage, mSender );
02394 return !mResult.isEmpty();
02395 }
02396 bool visit( Journal *journal )
02397 {
02398 mResult = invitationHeaderJournal( journal, mMessage );
02399 return !mResult.isEmpty();
02400 }
02401 bool visit( FreeBusy *fb )
02402 {
02403 mResult = invitationHeaderFreeBusy( fb, mMessage );
02404 return !mResult.isEmpty();
02405 }
02406 };
02407
02408 class IncidenceFormatter::InvitationBodyVisitor
02409 : public IncidenceFormatter::ScheduleMessageVisitor
02410 {
02411 public:
02412 InvitationBodyVisitor( bool noHtmlMode )
02413 : ScheduleMessageVisitor(), mNoHtmlMode( noHtmlMode ) {}
02414
02415 protected:
02416 bool visit( Event *event )
02417 {
02418 Event *oldevent = dynamic_cast<Event *>( mExistingIncidence );
02419 mResult = invitationDetailsEvent( event, oldevent, mNoHtmlMode );
02420 return !mResult.isEmpty();
02421 }
02422 bool visit( Todo *todo )
02423 {
02424 Todo *oldtodo = dynamic_cast<Todo *>( mExistingIncidence );
02425 mResult = invitationDetailsTodo( todo, oldtodo, mNoHtmlMode );
02426 return !mResult.isEmpty();
02427 }
02428 bool visit( Journal *journal )
02429 {
02430 Journal *oldjournal = dynamic_cast<Journal *>( mExistingIncidence );
02431 mResult = invitationDetailsJournal( journal, oldjournal, mNoHtmlMode );
02432 return !mResult.isEmpty();
02433 }
02434 bool visit( FreeBusy *fb )
02435 {
02436 mResult = invitationDetailsFreeBusy( fb, 0, mNoHtmlMode );
02437 return !mResult.isEmpty();
02438 }
02439
02440 private:
02441 bool mNoHtmlMode;
02442 };
02443
02444 class IncidenceFormatter::IncidenceCompareVisitor
02445 : public IncidenceBase::Visitor
02446 {
02447 public:
02448 IncidenceCompareVisitor() : mExistingIncidence(0) {}
02449 bool act( IncidenceBase *incidence, Incidence *existingIncidence, int method )
02450 {
02451 Incidence *inc = dynamic_cast<Incidence*>( incidence );
02452 if ( !inc || !existingIncidence || inc->revision() <= existingIncidence->revision() )
02453 return false;
02454 mExistingIncidence = existingIncidence;
02455 mMethod = method;
02456 return incidence->accept( *this );
02457 }
02458
02459 QString result() const
02460 {
02461 if ( mChanges.isEmpty() ) {
02462 return QString::null;
02463 }
02464 QString html = "<div align=\"left\"><ul><li>";
02465 html += mChanges.join( "</li><li>" );
02466 html += "</li><ul></div>";
02467 return html;
02468 }
02469
02470 protected:
02471 bool visit( Event *event )
02472 {
02473 compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
02474 compareIncidences( event, mExistingIncidence, mMethod );
02475 return !mChanges.isEmpty();
02476 }
02477 bool visit( Todo *todo )
02478 {
02479 compareTodos( todo, dynamic_cast<Todo*>( mExistingIncidence ) );
02480 compareIncidences( todo, mExistingIncidence, mMethod );
02481 return !mChanges.isEmpty();
02482 }
02483 bool visit( Journal *journal )
02484 {
02485 compareIncidences( journal, mExistingIncidence, mMethod );
02486 return !mChanges.isEmpty();
02487 }
02488 bool visit( FreeBusy *fb )
02489 {
02490 Q_UNUSED( fb );
02491 return !mChanges.isEmpty();
02492 }
02493
02494 private:
02495 void compareEvents( Event *newEvent, Event *oldEvent )
02496 {
02497 if ( !oldEvent || !newEvent )
02498 return;
02499 if ( oldEvent->dtStart() != newEvent->dtStart() || oldEvent->doesFloat() != newEvent->doesFloat() )
02500 mChanges += i18n( "The invitation starting time has been changed from %1 to %2" )
02501 .arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
02502 if ( oldEvent->dtEnd() != newEvent->dtEnd() || oldEvent->doesFloat() != newEvent->doesFloat() )
02503 mChanges += i18n( "The invitation ending time has been changed from %1 to %2" )
02504 .arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
02505 }
02506
02507 void compareTodos( Todo *newTodo, Todo *oldTodo )
02508 {
02509 if ( !oldTodo || !newTodo ) {
02510 return;
02511 }
02512
02513 if ( !oldTodo->isCompleted() && newTodo->isCompleted() ) {
02514 mChanges += i18n( "The task has been completed" );
02515 }
02516 if ( oldTodo->isCompleted() && !newTodo->isCompleted() ) {
02517 mChanges += i18n( "The task is no longer completed" );
02518 }
02519 if ( oldTodo->percentComplete() != newTodo->percentComplete() ) {
02520 const QString oldPer = i18n( "%1%" ).arg( oldTodo->percentComplete() );
02521 const QString newPer = i18n( "%1%" ).arg( newTodo->percentComplete() );
02522 mChanges += i18n( "The task completed percentage has changed from %1 to %2" ).
02523 arg( oldPer, newPer );
02524 }
02525
02526 if ( !oldTodo->hasStartDate() && newTodo->hasStartDate() ) {
02527 mChanges += i18n( "A task starting time has been added" );
02528 }
02529 if ( oldTodo->hasStartDate() && !newTodo->hasStartDate() ) {
02530 mChanges += i18n( "The task starting time has been removed" );
02531 }
02532 if ( oldTodo->hasStartDate() && newTodo->hasStartDate() &&
02533 oldTodo->dtStart() != newTodo->dtStart() ) {
02534 mChanges += i18n( "The task starting time has been changed from %1 to %2" ).
02535 arg( dateTimeToString( oldTodo->dtStart(), oldTodo->doesFloat(), false ),
02536 dateTimeToString( newTodo->dtStart(), newTodo->doesFloat(), false ) );
02537 }
02538
02539 if ( !oldTodo->hasDueDate() && newTodo->hasDueDate() ) {
02540 mChanges += i18n( "A task due time has been added" );
02541 }
02542 if ( oldTodo->hasDueDate() && !newTodo->hasDueDate() ) {
02543 mChanges += i18n( "The task due time has been removed" );
02544 }
02545 if ( oldTodo->hasDueDate() && newTodo->hasDueDate() &&
02546 oldTodo->dtDue() != newTodo->dtDue() ) {
02547 mChanges += i18n( "The task due time has been changed from %1 to %2" ).
02548 arg( dateTimeToString( oldTodo->dtDue(), oldTodo->doesFloat(), false ),
02549 dateTimeToString( newTodo->dtDue(), newTodo->doesFloat(), false ) );
02550 }
02551 }
02552
02553 void compareIncidences( Incidence *newInc, Incidence *oldInc, int method )
02554 {
02555 if ( !oldInc || !newInc )
02556 return;
02557 if ( oldInc->summary() != newInc->summary() )
02558 mChanges += i18n( "The summary has been changed to: \"%1\"" ).arg( newInc->summary() );
02559 if ( oldInc->location() != newInc->location() )
02560 mChanges += i18n( "The location has been changed to: \"%1\"" ).arg( newInc->location() );
02561 if ( oldInc->description() != newInc->description() )
02562 mChanges += i18n( "The description has been changed to: \"%1\"" ).arg( newInc->description() );
02563 Attendee::List oldAttendees = oldInc->attendees();
02564 Attendee::List newAttendees = newInc->attendees();
02565 for ( Attendee::List::ConstIterator it = newAttendees.constBegin();
02566 it != newAttendees.constEnd(); ++it ) {
02567 Attendee *oldAtt = oldInc->attendeeByMail( (*it)->email() );
02568 if ( !oldAtt ) {
02569 mChanges += i18n( "Attendee %1 has been added" ).arg( (*it)->fullName() );
02570 } else {
02571 if ( oldAtt->status() != (*it)->status() )
02572 mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).
02573 arg( (*it)->fullName() ).arg( (*it)->statusStr() );
02574 }
02575 }
02576 if ( method == Scheduler::Request ) {
02577 for ( Attendee::List::ConstIterator it = oldAttendees.constBegin();
02578 it != oldAttendees.constEnd(); ++it ) {
02579 if ( !attendeeIsOrganizer( oldInc, (*it) ) ) {
02580 Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
02581 if ( !newAtt ) {
02582 mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
02583 }
02584 }
02585 }
02586 }
02587 }
02588
02589 private:
02590 Incidence *mExistingIncidence;
02591 int mMethod;
02592 QStringList mChanges;
02593 };
02594
02595
02596 QString InvitationFormatterHelper::makeLink( const QString &id, const QString &text )
02597 {
02598 if ( !id.startsWith( "ATTACH:" ) ) {
02599 QString res = QString( "<a href=\"%1\"><b>%2</b></a>" ).
02600 arg( generateLinkURL( id ), text );
02601 return res;
02602 } else {
02603
02604 QString res = QString( "<a href=\"%1\">%2</a>" ).
02605 arg( generateLinkURL( id ), text );
02606 return res;
02607 }
02608 }
02609
02610 static QString responseButtons( Incidence *inc, bool rsvpReq, bool rsvpRec,
02611 InvitationFormatterHelper *helper )
02612 {
02613
02614 const QString spacer = "<td> </td>";
02615
02616 const QString tdOpen = "<td>";
02617 const QString tdClose = "</td>" + spacer;
02618
02619 QString html;
02620 if ( !helper ) {
02621 return html;
02622 }
02623
02624 if ( !rsvpReq && ( inc && inc->revision() == 0 ) ) {
02625
02626 html += tdOpen;
02627 html += helper->makeLink( "record", i18n( "[Record]" ) );
02628 html += tdClose;
02629
02630
02631 html += tdOpen;
02632 html += helper->makeLink( "delete", i18n( "[Move to Trash]" ) );
02633 html += tdClose;
02634
02635 } else {
02636
02637
02638 html += tdOpen;
02639 html += helper->makeLink( "accept", i18n( "[Accept]" ) );
02640 html += tdClose;
02641
02642
02643 html += tdOpen;
02644 html += helper->makeLink( "accept_conditionally",
02645 i18n( "Accept conditionally", "[Accept cond.]" ) );
02646 html += tdClose;
02647
02648
02649 html += tdOpen;
02650 html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
02651 html += tdClose;
02652
02653
02654 html += tdOpen;
02655 html += helper->makeLink( "decline", i18n( "[Decline]" ) );
02656 html += tdClose;
02657 }
02658
02659 if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
02660
02661 html += tdOpen;
02662 html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
02663 html += tdClose;
02664
02665
02666 html += tdOpen;
02667 html += helper->makeLink( "forward", i18n( "[Forward]" ) );
02668 html += tdClose;
02669
02670
02671 if ( inc && inc->type() == "Event" ) {
02672 html += tdOpen;
02673 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
02674 html += tdClose;
02675 }
02676 }
02677 return html;
02678 }
02679
02680 static QString counterButtons( Incidence *incidence,
02681 InvitationFormatterHelper *helper )
02682 {
02683
02684 const QString spacer = "<td> </td>";
02685
02686 const QString tdOpen = "<td>";
02687 const QString tdClose = "</td>" + spacer;
02688
02689 QString html;
02690 if ( !helper ) {
02691 return html;
02692 }
02693
02694
02695 html += tdOpen;
02696 html += helper->makeLink( "accept_counter", i18n("[Accept]") );
02697 html += tdClose;
02698
02699
02700 html += tdOpen;
02701 html += helper->makeLink( "decline_counter", i18n("[Decline]") );
02702 html += tdClose;
02703
02704
02705 if ( incidence && incidence->type() == "Event" ) {
02706 html += tdOpen;
02707 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
02708 html += tdClose;
02709 }
02710 return html;
02711 }
02712
02713 QString IncidenceFormatter::formatICalInvitationHelper( QString invitation,
02714 Calendar *mCalendar,
02715 InvitationFormatterHelper *helper,
02716 bool noHtmlMode,
02717 const QString &sender,
02718 bool outlookCompareStyle )
02719 {
02720 if ( invitation.isEmpty() ) {
02721 return QString::null;
02722 }
02723
02724 ICalFormat format;
02725
02726 ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
02727
02728 if( !msg ) {
02729 kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
02730 Q_ASSERT( format.exception() );
02731 kdDebug( 5850 ) << format.exception()->message() << endl;
02732 return QString::null;
02733 }
02734
02735 IncidenceBase *incBase = msg->event();
02736
02737
02738 Incidence *existingIncidence = 0;
02739 if ( incBase && helper->calendar() ) {
02740 existingIncidence = helper->calendar()->incidence( incBase->uid() );
02741 if ( !CalHelper::isMyCalendarIncidence( helper->calendar(), existingIncidence ) ) {
02742 existingIncidence = 0;
02743 }
02744 if ( !existingIncidence ) {
02745 const Incidence::List list = helper->calendar()->incidences();
02746 for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
02747 if ( (*it)->schedulingID() == incBase->uid() &&
02748 CalHelper::isMyCalendarIncidence( helper->calendar(), *it ) ) {
02749 existingIncidence = *it;
02750 break;
02751 }
02752 }
02753 }
02754 }
02755
02756
02757 QString html;
02758
02759 QString tableStyle = QString::fromLatin1(
02760 "style=\"border: solid 1px; margin: 0em;\"" );
02761 QString tableHead = QString::fromLatin1(
02762 "<div align=\"center\">"
02763 "<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
02764 "<tr><td>").arg(tableStyle);
02765
02766 html += tableHead;
02767 InvitationHeaderVisitor headerVisitor;
02768
02769 if ( !headerVisitor.act( incBase, existingIncidence, msg, sender ) ) {
02770 return QString::null;
02771 }
02772 html += "<b>" + headerVisitor.result() + "</b>";
02773
02774 if ( outlookCompareStyle ) {
02775
02776 InvitationBodyVisitor bodyVisitor( noHtmlMode );
02777 if ( msg->method() == Scheduler::Request || msg->method() == Scheduler::Reply ) {
02778 if ( !bodyVisitor.act( incBase, existingIncidence, msg, sender ) ) {
02779 return QString::null;
02780 }
02781 } else {
02782 if ( !bodyVisitor.act( incBase, 0, msg, sender ) ) {
02783 return QString::null;
02784 }
02785 }
02786 html += bodyVisitor.result();
02787 } else {
02788
02789 InvitationBodyVisitor bodyVisitor( noHtmlMode );
02790 if ( !bodyVisitor.act( incBase, 0, msg, sender ) )
02791 return QString::null;
02792 html += bodyVisitor.result();
02793
02794 if ( msg->method() == Scheduler::Request ) {
02795 IncidenceCompareVisitor compareVisitor;
02796 if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
02797 html += "<p align=\"left\">";
02798 html += i18n( "The following changes have been made by the organizer:" );
02799 html += "</p>";
02800 html += compareVisitor.result();
02801 }
02802 }
02803 if ( msg->method() == Scheduler::Reply ) {
02804 IncidenceCompareVisitor compareVisitor;
02805 if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
02806 html += "<p align=\"left\">";
02807 if ( !sender.isEmpty() ) {
02808 html += i18n( "The following changes have been made by %1:" ).arg( sender );
02809 } else {
02810 html += i18n( "The following changes have been made by an attendee:" );
02811 }
02812 html += "</p>";
02813 html += compareVisitor.result();
02814 }
02815 }
02816 }
02817
02818 Incidence *inc = dynamic_cast<Incidence*>( incBase );
02819
02820
02821 bool myInc = iamOrganizer( inc );
02822
02823
02824 bool rsvpRec = false;
02825 Attendee *ea = 0;
02826 if ( !myInc ) {
02827 Incidence *rsvpIncidence = existingIncidence;
02828 if ( !rsvpIncidence && inc && inc->revision() > 0 ) {
02829 rsvpIncidence = inc;
02830 }
02831 if ( rsvpIncidence ) {
02832 ea = findMyAttendee( rsvpIncidence );
02833 }
02834 if ( ea &&
02835 ( ea->status() == Attendee::Accepted ||
02836 ea->status() == Attendee::Declined ||
02837 ea->status() == Attendee::Tentative ) ) {
02838 rsvpRec = true;
02839 }
02840 }
02841
02842
02843 QString role;
02844 bool isDelegated = false;
02845 Attendee *a = findMyAttendee( inc );
02846 if ( !a && inc ) {
02847 if ( !inc->attendees().isEmpty() ) {
02848 a = inc->attendees().first();
02849 }
02850 }
02851 if ( a ) {
02852 isDelegated = ( a->status() == Attendee::Delegated );
02853 role = Attendee::roleName( a->role() );
02854 }
02855
02856
02857 bool rsvpReq = rsvpRequested( inc );
02858 if ( !myInc && a ) {
02859 html += "<br/>";
02860 html += "<i><u>";
02861 if ( rsvpRec && inc ) {
02862 if ( inc->revision() == 0 ) {
02863 html += i18n( "Your <b>%1</b> response has been recorded" ).
02864 arg( ea->statusStr() );
02865 } else {
02866 html += i18n( "Your status for this invitation is <b>%1</b>" ).
02867 arg( ea->statusStr() );
02868 }
02869 rsvpReq = false;
02870 } else if ( msg->method() == Scheduler::Cancel ) {
02871 html += i18n( "This invitation was canceled" );
02872 } else if ( msg->method() == Scheduler::Add ) {
02873 html += i18n( "This invitation was accepted" );
02874 } else {
02875 if ( !isDelegated ) {
02876 html += rsvpRequestedStr( rsvpReq, role );
02877 } else {
02878 html += i18n( "Awaiting delegation response" );
02879 }
02880 }
02881 html += "</u></i>";
02882 }
02883
02884
02885 if ( !myInc ) {
02886 if ( inc && inc->revision() == 0 ) {
02887 QString statStr = myStatusStr( inc );
02888 if ( !statStr.isEmpty() ) {
02889 html += "<br/>";
02890 html += "<i>";
02891 html += statStr;
02892 html += "</i>";
02893 }
02894 }
02895 }
02896
02897
02898
02899 html += "<br><table border=\"0\" cellspacing=\"0\"><tr><td> </td></tr>";
02900
02901 switch ( msg->method() ) {
02902 case Scheduler::Publish:
02903 case Scheduler::Request:
02904 case Scheduler::Refresh:
02905 case Scheduler::Add:
02906 {
02907 if ( inc && inc->revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
02908 html += "<tr>";
02909 if ( inc->type() == "Todo" ) {
02910 html += "<td colspan=\"9\">";
02911 html += helper->makeLink( "reply", i18n( "[Record invitation in my task list]" ) );
02912 } else {
02913 html += "<td colspan=\"13\">";
02914 html += helper->makeLink( "reply", i18n( "[Record invitation in my calendar]" ) );
02915 }
02916 html += "</td></tr>";
02917 }
02918
02919 if ( !myInc && a ) {
02920 html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
02921 }
02922 break;
02923 }
02924
02925 case Scheduler::Cancel:
02926
02927 if ( inc ) {
02928 html += "<tr>";
02929 if ( inc->type() == "Todo" ) {
02930 html += "<td colspan=\"9\">";
02931 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my task list]" ) );
02932 } else {
02933 html += "<td colspan=\"13\">";
02934 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my calendar]" ) );
02935 }
02936 html += "</td></tr>";
02937 }
02938 break;
02939
02940 case Scheduler::Reply:
02941 {
02942
02943 Attendee *a = 0;
02944 Attendee *ea = 0;
02945 if ( inc ) {
02946
02947 if ( replyMeansCounter( inc ) ) {
02948 html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
02949 break;
02950 }
02951
02952
02953
02954
02955
02956
02957 a = findDelegatedFromMyAttendee( inc );
02958 if ( a ) {
02959 if ( a->status() != Attendee::Accepted ||
02960 a->status() != Attendee::Tentative ) {
02961 html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
02962 break;
02963 }
02964 }
02965
02966
02967 if ( !inc->attendees().isEmpty() ) {
02968 a = inc->attendees().first();
02969 }
02970 if ( a ) {
02971 ea = findAttendee( existingIncidence, a->email() );
02972 }
02973 }
02974 if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
02975 if ( inc && inc->revision() > 0 ) {
02976 html += "<br><u><i>";
02977 html += i18n( "The <b>%1</b> response has been recorded" ).arg( ea->statusStr() );
02978 html += "</i></u>";
02979 }
02980 } else {
02981 if ( inc ) {
02982 html += "<tr><td>";
02983 if ( inc->type() == "Todo" ) {
02984 html += helper->makeLink( "reply", i18n( "[Record response in my task list]" ) );
02985 } else {
02986 html += helper->makeLink( "reply", i18n( "[Record response in my calendar]" ) );
02987 }
02988 html += "</td></tr>";
02989 }
02990 }
02991 break;
02992 }
02993
02994 case Scheduler::Counter:
02995
02996 html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
02997 break;
02998
02999 case Scheduler::Declinecounter:
03000 case Scheduler::NoMethod:
03001 break;
03002 }
03003
03004
03005 html += "</td></tr></table>";
03006
03007
03008 if ( helper->calendar() ) {
03009 if ( myInc ) {
03010
03011 html += invitationRsvpList( helper->calendar()->incidence( inc->uid() ), a );
03012 } else {
03013 html += invitationAttendeeList( helper->calendar()->incidence( inc->uid() ) );
03014 }
03015 }
03016
03017
03018 html += "</td></tr></table><br></div>";
03019
03020
03021 html += invitationAttachments( helper, inc );
03022
03023 return html;
03024 }
03025
03026 QString IncidenceFormatter::formatICalInvitation( QString invitation,
03027 Calendar *mCalendar,
03028 InvitationFormatterHelper *helper )
03029 {
03030 return formatICalInvitationHelper( invitation, mCalendar, helper, false, QString(), true );
03031 }
03032
03033 QString IncidenceFormatter::formatICalInvitationNoHtml( QString invitation,
03034 Calendar *mCalendar,
03035 InvitationFormatterHelper *helper )
03036 {
03037 return formatICalInvitationHelper( invitation, mCalendar, helper, true, QString(), true );
03038 }
03039
03040 QString IncidenceFormatter::formatICalInvitationNoHtml( QString invitation,
03041 Calendar *mCalendar,
03042 InvitationFormatterHelper *helper,
03043 const QString &sender )
03044 {
03045 return formatICalInvitationHelper( invitation, mCalendar, helper, true, sender, true );
03046 }
03047
03048 QString IncidenceFormatter::formatICalInvitationNoHtml( QString invitation,
03049 Calendar *mCalendar,
03050 InvitationFormatterHelper *helper,
03051 const QString &sender,
03052 bool outlookCompareStyle )
03053 {
03054 return formatICalInvitationHelper( invitation, mCalendar, helper, true, sender, outlookCompareStyle );
03055 }
03056
03057
03058
03059
03060
03061
03062
03063
03064 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
03065 const QString& fallback = QString::null)
03066 {
03067 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
03068 fallback );
03069 }
03070
03071 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
03072 const QString& fallback = QString::null )
03073 {
03074 return tnefMsg->findNamedProp( name, fallback );
03075 }
03076
03077 struct save_tz { char* old_tz; char* tz_env_str; };
03078
03079
03080 static struct save_tz set_tz( const char* _tc )
03081 {
03082 const char *tc = _tc?_tc:"UTC";
03083
03084 struct save_tz rv;
03085
03086 rv.old_tz = 0;
03087 rv.tz_env_str = 0;
03088
03089
03090
03091 char* tz_env = 0;
03092 if( getenv( "TZ" ) ) {
03093 tz_env = strdup( getenv( "TZ" ) );
03094 rv.old_tz = tz_env;
03095 }
03096 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
03097 strcpy( tmp_env, "TZ=" );
03098 strcpy( tmp_env+3, tc );
03099 putenv( tmp_env );
03100
03101 rv.tz_env_str = tmp_env;
03102
03103
03104
03105 tzset();
03106
03107
03108 return rv;
03109 }
03110
03111
03112 static void unset_tz( struct save_tz old_tz )
03113 {
03114 if( old_tz.old_tz ) {
03115 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
03116 strcpy( tmp_env, "TZ=" );
03117 strcpy( tmp_env+3, old_tz.old_tz );
03118 putenv( tmp_env );
03119
03120 free( old_tz.old_tz );
03121 } else {
03122
03123 putenv( strdup("TZ") );
03124 }
03125 tzset();
03126
03127
03128 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
03129 }
03130
03131 static QDateTime utc2Local( const QDateTime& utcdt )
03132 {
03133 struct tm tmL;
03134
03135 save_tz tmp_tz = set_tz("UTC");
03136 time_t utc = utcdt.toTime_t();
03137 unset_tz( tmp_tz );
03138
03139 localtime_r( &utc, &tmL );
03140 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
03141 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
03142 }
03143
03144
03145 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
03146 bool bDateOnly = false )
03147 {
03148 QDate tmpDate;
03149 QTime tmpTime;
03150 int year, month, day, hour, minute, second;
03151
03152 if( bDateOnly ) {
03153 year = dtStr.left( 4 ).toInt();
03154 month = dtStr.mid( 4, 2 ).toInt();
03155 day = dtStr.mid( 6, 2 ).toInt();
03156 hour = 0;
03157 minute = 0;
03158 second = 0;
03159 } else {
03160 year = dtStr.left( 4 ).toInt();
03161 month = dtStr.mid( 4, 2 ).toInt();
03162 day = dtStr.mid( 6, 2 ).toInt();
03163 hour = dtStr.mid( 9, 2 ).toInt();
03164 minute = dtStr.mid( 11, 2 ).toInt();
03165 second = dtStr.mid( 13, 2 ).toInt();
03166 }
03167 tmpDate.setYMD( year, month, day );
03168 tmpTime.setHMS( hour, minute, second );
03169
03170 if( tmpDate.isValid() && tmpTime.isValid() ) {
03171 QDateTime dT = QDateTime( tmpDate, tmpTime );
03172
03173 if( !bDateOnly ) {
03174
03175 if (dtStr.at(dtStr.length()-1) == 'Z') {
03176
03177
03178 dT = utc2Local( dT );
03179 }
03180 }
03181 return dT;
03182 } else
03183 return QDateTime();
03184 }
03185
03186
03187
03188 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
03189 {
03190 bool bOk = false;
03191
03192 KTNEFParser parser;
03193 QBuffer buf( tnef );
03194 CalendarLocal cal ( QString::fromLatin1( "UTC" ) );
03195 KABC::Addressee addressee;
03196 KABC::VCardConverter cardConv;
03197 ICalFormat calFormat;
03198 Event* event = new Event();
03199
03200 if( parser.openDevice( &buf ) ) {
03201 KTNEFMessage* tnefMsg = parser.message();
03202
03203
03204
03205
03206 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
03207 .upper();
03208 if( !msgClass.isEmpty() ) {
03209
03210
03211 bool bCompatClassAppointment = false;
03212 bool bCompatMethodRequest = false;
03213 bool bCompatMethodCancled = false;
03214 bool bCompatMethodAccepted = false;
03215 bool bCompatMethodAcceptedCond = false;
03216 bool bCompatMethodDeclined = false;
03217 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
03218 bCompatClassAppointment = true;
03219 if( msgClass.endsWith( ".MTGREQ" ) )
03220 bCompatMethodRequest = true;
03221 if( msgClass.endsWith( ".MTGCNCL" ) )
03222 bCompatMethodCancled = true;
03223 if( msgClass.endsWith( ".MTGRESPP" ) )
03224 bCompatMethodAccepted = true;
03225 if( msgClass.endsWith( ".MTGRESPA" ) )
03226 bCompatMethodAcceptedCond = true;
03227 if( msgClass.endsWith( ".MTGRESPN" ) )
03228 bCompatMethodDeclined = true;
03229 }
03230 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
03231
03232 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
03233
03234 bool bIsReply = false;
03235 QString prodID = "-//Microsoft Corporation//Outlook ";
03236 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
03237 prodID += "MIMEDIR/EN\n";
03238 prodID += "VERSION:2.0\n";
03239 calFormat.setApplication( "Outlook", prodID );
03240
03241 Scheduler::Method method;
03242 if( bCompatMethodRequest )
03243 method = Scheduler::Request;
03244 else if( bCompatMethodCancled )
03245 method = Scheduler::Cancel;
03246 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
03247 bCompatMethodDeclined ) {
03248 method = Scheduler::Reply;
03249 bIsReply = true;
03250 } else {
03251
03252
03253
03254
03255
03256
03257
03258
03259 if( tnefMsg->findProp(0x0c17) == "1" )
03260 bIsReply = true;
03261 method = Scheduler::Request;
03262 }
03263
03265 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
03266
03267 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
03268
03269 if( !sSenderSearchKeyEmail.isEmpty() ) {
03270 int colon = sSenderSearchKeyEmail.find( ':' );
03271
03272 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
03273 sSenderSearchKeyEmail.remove( 0, colon+1 );
03274 }
03275
03276 QString s( tnefMsg->findProp( 0x0e04 ) );
03277 QStringList attendees = QStringList::split( ';', s );
03278 if( attendees.count() ) {
03279 for( QStringList::Iterator it = attendees.begin();
03280 it != attendees.end(); ++it ) {
03281
03282
03283 if( (*it).find('@') == -1 ) {
03284 s = (*it).stripWhiteSpace();
03285
03286 Attendee *attendee = new Attendee( s, s, true );
03287 if( bIsReply ) {
03288 if( bCompatMethodAccepted )
03289 attendee->setStatus( Attendee::Accepted );
03290 if( bCompatMethodDeclined )
03291 attendee->setStatus( Attendee::Declined );
03292 if( bCompatMethodAcceptedCond )
03293 attendee->setStatus(Attendee::Tentative);
03294 } else {
03295 attendee->setStatus( Attendee::NeedsAction );
03296 attendee->setRole( Attendee::ReqParticipant );
03297 }
03298 event->addAttendee(attendee);
03299 }
03300 }
03301 } else {
03302
03303
03304 s = sSenderSearchKeyEmail;
03305 if( !s.isEmpty() ) {
03306 Attendee *attendee = new Attendee( QString::null, QString::null,
03307 true );
03308 if( bIsReply ) {
03309 if( bCompatMethodAccepted )
03310 attendee->setStatus( Attendee::Accepted );
03311 if( bCompatMethodAcceptedCond )
03312 attendee->setStatus( Attendee::Declined );
03313 if( bCompatMethodDeclined )
03314 attendee->setStatus( Attendee::Tentative );
03315 } else {
03316 attendee->setStatus(Attendee::NeedsAction);
03317 attendee->setRole(Attendee::ReqParticipant);
03318 }
03319 event->addAttendee(attendee);
03320 }
03321 }
03322 s = tnefMsg->findProp( 0x0c1f );
03323 if( s.isEmpty() && !bIsReply )
03324 s = sSenderSearchKeyEmail;
03325
03326 if( !s.isEmpty() )
03327 event->setOrganizer( s );
03328
03329 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
03330 .replace( QChar( ':' ), QString::null );
03331 event->setDtStart( QDateTime::fromString( s ) );
03332
03333 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
03334 .replace( QChar( ':' ), QString::null );
03335 event->setDtEnd( QDateTime::fromString( s ) );
03336
03337 s = tnefMsg->findProp( 0x8208 );
03338 event->setLocation( s );
03339
03340
03341
03342
03343
03344
03345 s = tnefMsg->findProp( 0x0023 );
03346 event->setUid( s );
03347
03348
03349
03350
03351 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
03352 .replace( QChar( ':' ), QString::null );
03353
03354
03355
03356 s = tnefMsg->findNamedProp( "Keywords" );
03357 event->setCategories( s );
03358
03359 s = tnefMsg->findProp( 0x1000 );
03360 event->setDescription( s );
03361
03362 s = tnefMsg->findProp( 0x0070 );
03363 event->setSummary( s );
03364
03365 s = tnefMsg->findProp( 0x0026 );
03366 event->setPriority( s.toInt() );
03367
03368
03369 if(!tnefMsg->findProp(0x8503).isEmpty()) {
03370 Alarm *alarm = new Alarm(event);
03371 QDateTime highNoonTime =
03372 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
03373 .replace( QChar( '-' ), "" )
03374 .replace( QChar( ':' ), "" ) );
03375 QDateTime wakeMeUpTime =
03376 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
03377 .replace( QChar( '-' ), "" )
03378 .replace( QChar( ':' ), "" ) );
03379 alarm->setTime(wakeMeUpTime);
03380
03381 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
03382 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
03383 else
03384
03385 alarm->setStartOffset( Duration( 15*60 ) );
03386 alarm->setDisplayAlarm( i18n( "Reminder" ) );
03387
03388
03389
03390 event->addAlarm( alarm );
03391 }
03392 cal.addEvent( event );
03393 bOk = true;
03394
03395 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
03396 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
03397 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
03398 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
03399 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
03400 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
03401 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
03402 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
03403 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
03404 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
03405 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
03406 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
03407 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
03408
03409 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
03410 .replace( QChar( '-' ), QString::null )
03411 .replace( QChar( ':' ), QString::null );
03412 if( !s.isEmpty() )
03413 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
03414
03415 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
03416
03417
03418 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
03419 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
03420 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
03421 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
03422 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
03423
03424 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
03425 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
03426 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
03427
03428
03429
03430
03431
03432 KABC::Address adr;
03433 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
03434 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
03435 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
03436 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
03437 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
03438 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
03439 adr.setType(KABC::Address::Home);
03440 addressee.insertAddress(adr);
03441
03442 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
03443 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
03444 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
03445 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
03446 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
03447 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
03448 adr.setType( KABC::Address::Work );
03449 addressee.insertAddress( adr );
03450
03451 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
03452 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
03453 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
03454 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
03455 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
03456 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
03457 adr.setType( KABC::Address::Dom );
03458 addressee.insertAddress(adr);
03459
03460
03461
03462
03463
03464 QString nr;
03465 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
03466 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
03467 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
03468 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
03469 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
03470 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
03471 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
03472 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
03473 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
03474 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
03475
03476 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
03477 .replace( QChar( '-' ), QString::null )
03478 .replace( QChar( ':' ), QString::null );
03479 if( !s.isEmpty() )
03480 addressee.setBirthday( QDateTime::fromString( s ) );
03481
03482 bOk = ( !addressee.isEmpty() );
03483 } else if( "IPM.NOTE" == msgClass ) {
03484
03485 }
03486 }
03487 }
03488
03489
03490 QString iCal = calFormat.toString( &cal );
03491 if( !iCal.isEmpty() )
03492
03493 return iCal;
03494
03495
03496 KABC::VCardConverter converter;
03497 return converter.createVCard( addressee );
03498 }
03499
03500
03501 QString IncidenceFormatter::formatTNEFInvitation( const QByteArray& tnef,
03502 Calendar *mCalendar, InvitationFormatterHelper *helper )
03503 {
03504 QString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
03505 QString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
03506 if( !iCal.isEmpty() )
03507 return iCal;
03508 return vPart;
03509 }
03510
03511
03512
03513
03514
03515
03516
03517
03518 class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
03519 {
03520 public:
03521 ToolTipVisitor()
03522 : mCalendar( 0 ), mRichText( true ), mResult( "" ) {}
03523
03524 bool act( Calendar *calendar, IncidenceBase *incidence,
03525 const QDate &date=QDate(), bool richText=true )
03526 {
03527 mCalendar = calendar;
03528 mDate = date;
03529 mRichText = richText;
03530 mResult = "";
03531 return incidence ? incidence->accept( *this ) : false;
03532 }
03533 QString result() const { return mResult; }
03534
03535 protected:
03536 bool visit( Event *event );
03537 bool visit( Todo *todo );
03538 bool visit( Journal *journal );
03539 bool visit( FreeBusy *fb );
03540
03541 QString dateRangeText( Event *event, const QDate &date );
03542 QString dateRangeText( Todo *todo, const QDate &date );
03543 QString dateRangeText( Journal *journal );
03544 QString dateRangeText( FreeBusy *fb );
03545
03546 QString generateToolTip( Incidence* incidence, QString dtRangeText );
03547
03548 protected:
03549 Calendar *mCalendar;
03550 QDate mDate;
03551 bool mRichText;
03552 QString mResult;
03553 };
03554
03555 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event *event, const QDate &date )
03556 {
03557 QString ret;
03558 QString tmp;
03559
03560 QDateTime startDt = event->dtStart();
03561 QDateTime endDt = event->dtEnd();
03562 if ( event->doesRecur() ) {
03563 if ( date.isValid() ) {
03564 QDateTime dt( date, QTime( 0, 0, 0 ) );
03565 int diffDays = startDt.daysTo( dt );
03566 dt = dt.addSecs( -1 );
03567 startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
03568 if ( event->hasEndDate() ) {
03569 endDt = endDt.addDays( diffDays );
03570 if ( startDt > endDt ) {
03571 startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
03572 endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
03573 }
03574 }
03575 }
03576 }
03577 if ( event->isMultiDay() ) {
03578
03579 tmp = "<br>" + i18n("Event start", "<i>From:</i> %1");
03580 if (event->doesFloat())
03581 ret += tmp.arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", " ") );
03582 else
03583 ret += tmp.arg( IncidenceFormatter::dateToString( startDt ).replace(" ", " ") );
03584
03585 tmp = "<br>" + i18n("Event end","<i>To:</i> %1");
03586 if (event->doesFloat())
03587 ret += tmp.arg( IncidenceFormatter::dateToString( endDt, false ).replace(" ", " ") );
03588 else
03589 ret += tmp.arg( IncidenceFormatter::dateToString( endDt ).replace(" ", " ") );
03590
03591 } else {
03592
03593 ret += "<br>"+i18n("<i>Date:</i> %1").
03594 arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", " ") );
03595 if ( !event->doesFloat() ) {
03596 const QString dtStartTime =
03597 IncidenceFormatter::timeToString( startDt, true ).replace( " ", " " );
03598 const QString dtEndTime =
03599 IncidenceFormatter::timeToString( endDt, true ).replace( " ", " " );
03600 if ( dtStartTime == dtEndTime ) {
03601 tmp = "<br>" + i18n("time for event, to prevent ugly line breaks",
03602 "<i>Time:</i> %1").
03603 arg( dtStartTime );
03604 } else {
03605 tmp = "<br>" + i18n("time range for event, to prevent ugly line breaks",
03606 "<i>Time:</i> %1 - %2").
03607 arg( dtStartTime, dtEndTime );
03608 }
03609 ret += tmp;
03610 }
03611
03612 }
03613 return ret;
03614 }
03615
03616 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo *todo, const QDate &date )
03617 {
03618 QString ret;
03619 bool floats( todo->doesFloat() );
03620
03621 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
03622 QDateTime startDt = todo->dtStart();
03623 if ( todo->doesRecur() ) {
03624 if ( date.isValid() ) {
03625 startDt.setDate( date );
03626 }
03627 }
03628 ret += "<br>" +
03629 i18n("<i>Start:</i> %1").
03630 arg( IncidenceFormatter::dateTimeToString( startDt, floats, false ).
03631 replace( " ", " " ) );
03632 }
03633
03634 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
03635 QDateTime dueDt = todo->dtDue();
03636 if ( todo->doesRecur() ) {
03637 if ( date.isValid() ) {
03638 QDateTime dt( date, QTime( 0, 0, 0 ) );
03639 dt = dt.addSecs( -1 );
03640 dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
03641 }
03642 }
03643 ret += "<br>" +
03644 i18n("<i>Due:</i> %1").
03645 arg( IncidenceFormatter::dateTimeToString( dueDt, floats, false ).
03646 replace( " ", " " ) );
03647 }
03648
03649
03650
03651 if ( todo->priority() > 0 ) {
03652 ret += "<br>";
03653 ret += "<i>" + i18n( "Priority:" ) + "</i>" + " ";
03654 ret += QString::number( todo->priority() );
03655 }
03656
03657 ret += "<br>";
03658 if ( todo->isCompleted() ) {
03659 ret += "<i>" + i18n( "Completed:" ) + "</i>" + " ";
03660 ret += todo->completedStr().replace( " ", " " );
03661 } else {
03662 ret += "<i>" + i18n( "Percent Done:" ) + "</i>" + " ";
03663 ret += i18n( "%1%" ).arg( todo->percentComplete() );
03664 }
03665
03666 return ret;
03667 }
03668
03669 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
03670 {
03671 QString ret;
03672 if (journal->dtStart().isValid() ) {
03673 ret += "<br>" +
03674 i18n("<i>Date:</i> %1").
03675 arg( IncidenceFormatter::dateToString( journal->dtStart(), false ) );
03676 }
03677 return ret;
03678 }
03679
03680 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
03681 {
03682 QString tmp( "<br>" + i18n("<i>Period start:</i> %1") );
03683 QString ret = tmp.arg( KGlobal::locale()->formatDateTime( fb->dtStart() ) );
03684 tmp = "<br>" + i18n("<i>Period start:</i> %1");
03685 ret += tmp.arg( KGlobal::locale()->formatDateTime( fb->dtEnd() ) );
03686 return ret;
03687 }
03688
03689 bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
03690 {
03691 mResult = generateToolTip( event, dateRangeText( event, mDate ) );
03692 return !mResult.isEmpty();
03693 }
03694
03695 bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
03696 {
03697 mResult = generateToolTip( todo, dateRangeText( todo, mDate ) );
03698 return !mResult.isEmpty();
03699 }
03700
03701 bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
03702 {
03703 mResult = generateToolTip( journal, dateRangeText( journal ) );
03704 return !mResult.isEmpty();
03705 }
03706
03707 bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
03708 {
03709 mResult = "<qt><b>" + i18n("Free/Busy information for %1")
03710 .arg(fb->organizer().fullName()) + "</b>";
03711 mResult += dateRangeText( fb );
03712 mResult += "</qt>";
03713 return !mResult.isEmpty();
03714 }
03715
03716 static QString tooltipPerson( const QString &email, const QString &name, Attendee::PartStat status )
03717 {
03718
03719 const QString printName = searchName( email, name );
03720
03721
03722 const QString iconPath = rsvpStatusIconPath( status );
03723
03724
03725 QString personString;
03726 if ( !iconPath.isEmpty() ) {
03727 personString += "<img valign=\"top\" src=\"" + iconPath + "\">" + " ";
03728 }
03729 if ( status != Attendee::None ) {
03730 personString += i18n( "attendee name (attendee status)", "%1 (%2)" ).
03731 arg( printName.isEmpty() ? email : printName ).
03732 arg( Attendee::statusName( status ) );
03733 } else {
03734 personString += i18n( "%1" ).arg( printName.isEmpty() ? email : printName );
03735 }
03736 return personString;
03737 }
03738
03739 static QString tooltipFormatOrganizer( const QString &email, const QString &name )
03740 {
03741
03742 const QString printName = searchName( email, name );
03743
03744
03745 const QString iconPath = KGlobal::iconLoader()->iconPath( "organizer", KIcon::Small );
03746
03747
03748 QString personString;
03749 personString += "<img valign=\"top\" src=\"" + iconPath + "\">" + " ";
03750 personString += ( printName.isEmpty() ? email : printName );
03751 return personString;
03752 }
03753
03754 static QString tooltipFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role,
03755 bool showStatus )
03756 {
03757 const int maxNumAtts = 8;
03758 const QString etc = i18n( "elipsis", "..." );
03759
03760 int i = 0;
03761 QString tmpStr;
03762 Attendee::List::ConstIterator it;
03763 Attendee::List attendees = incidence->attendees();
03764
03765 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
03766 Attendee *a = *it;
03767 if ( a->role() != role ) {
03768
03769 continue;
03770 }
03771 if ( attendeeIsOrganizer( incidence, a ) ) {
03772
03773 continue;
03774 }
03775 if ( i == maxNumAtts ) {
03776 tmpStr += " " + etc;
03777 break;
03778 }
03779 tmpStr += " " + tooltipPerson( a->email(), a->name(),
03780 showStatus ? a->status() : Attendee::None );
03781 if ( !a->delegator().isEmpty() ) {
03782 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
03783 }
03784 if ( !a->delegate().isEmpty() ) {
03785 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
03786 }
03787 tmpStr += "<br>";
03788 i++;
03789 }
03790
03791 if ( tmpStr.endsWith( "<br>" ) ) {
03792 tmpStr.truncate( tmpStr.length() - 4 );
03793 }
03794 return tmpStr;
03795 }
03796
03797 static QString tooltipFormatAttendees( Calendar *calendar, Incidence *incidence )
03798 {
03799 QString tmpStr, str;
03800
03801
03802 int attendeeCount = incidence->attendees().count();
03803 if ( attendeeCount > 1 ||
03804 ( attendeeCount == 1 &&
03805 !attendeeIsOrganizer( incidence, incidence->attendees().first() ) ) ) {
03806 tmpStr += "<i>" + i18n( "Organizer:" ) + "</i>" + "<br>";
03807 tmpStr += " " + tooltipFormatOrganizer( incidence->organizer().email(),
03808 incidence->organizer().name() );
03809 }
03810
03811
03812
03813 bool showStatus = CalHelper::incOrganizerOwnsCalendar( calendar, incidence );
03814
03815
03816 str = tooltipFormatAttendeeRoleList( incidence, Attendee::Chair, showStatus );
03817 if ( !str.isEmpty() ) {
03818 tmpStr += "<br><i>" + i18n( "Chair:" ) + "</i>" + "<br>";
03819 tmpStr += str;
03820 }
03821
03822
03823 str = tooltipFormatAttendeeRoleList( incidence, Attendee::ReqParticipant, showStatus );
03824 if ( !str.isEmpty() ) {
03825 tmpStr += "<br><i>" + i18n( "Required Participants:" ) + "</i>" + "<br>";
03826 tmpStr += str;
03827 }
03828
03829
03830 str = tooltipFormatAttendeeRoleList( incidence, Attendee::OptParticipant, showStatus );
03831 if ( !str.isEmpty() ) {
03832 tmpStr += "<br><i>" + i18n( "Optional Participants:" ) + "</i>" + "<br>";
03833 tmpStr += str;
03834 }
03835
03836
03837 str = tooltipFormatAttendeeRoleList( incidence, Attendee::NonParticipant, showStatus );
03838 if ( !str.isEmpty() ) {
03839 tmpStr += "<br><i>" + i18n( "Observers:" ) + "</i>" + "<br>";
03840 tmpStr += str;
03841 }
03842
03843 return tmpStr;
03844 }
03845
03846 QString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence *incidence, QString dtRangeText )
03847 {
03848 const QString etc = i18n( "elipsis", "..." );
03849 const uint maxDescLen = 120;
03850
03851 if ( !incidence ) {
03852 return QString::null;
03853 }
03854
03855 QString tmp = "<qt>";
03856
03857
03858 tmp += "<b>" + incidence->summary().replace( "\n", "<br>" ) + "</b>";
03859
03860 tmp += "<br>----------<br>";
03861
03862 if ( mCalendar ) {
03863 QString calStr = IncidenceFormatter::resourceString( mCalendar, incidence );
03864 if ( !calStr.isEmpty() ) {
03865 tmp += "<i>" + i18n( "Calendar:" ) + "</i>" + " ";
03866 tmp += calStr;
03867 }
03868 }
03869
03870 tmp += dtRangeText;
03871
03872 if ( !incidence->location().isEmpty() ) {
03873 tmp += "<br>";
03874 tmp += "<i>" + i18n( "Location:" ) + "</i>" + " ";
03875 tmp += incidence->location().replace( "\n", "<br>" );
03876 }
03877
03878 QString durStr = IncidenceFormatter::durationString( incidence );
03879 if ( !durStr.isEmpty() ) {
03880 tmp += "<br>";
03881 tmp += "<i>" + i18n( "Duration:" ) + "</i>" + " ";
03882 tmp += durStr;
03883 }
03884
03885 if ( incidence->doesRecur() ) {
03886 tmp += "<br>";
03887 tmp += "<i>" + i18n( "Recurrence:" ) + "</i>" + " ";
03888 tmp += IncidenceFormatter::recurrenceString( incidence );
03889 }
03890
03891 if ( !incidence->description().isEmpty() ) {
03892 QString desc( incidence->description() );
03893 if ( desc.length() > maxDescLen ) {
03894 desc = desc.left( maxDescLen ) + etc;
03895 }
03896 tmp += "<br>----------<br>";
03897 tmp += "<i>" + i18n( "Description:" ) + "</i>" + "<br>";
03898 tmp += desc.replace( "\n", "<br>" );
03899 tmp += "<br>----------";
03900 }
03901
03902 int reminderCount = incidence->alarms().count();
03903 if ( reminderCount > 0 && incidence->isAlarmEnabled() ) {
03904 tmp += "<br>";
03905 tmp += "<i>" + i18n( "Reminder:", "%n Reminders:", reminderCount ) + "</i>" + " ";
03906 tmp += IncidenceFormatter::reminderStringList( incidence ).join( ", " );
03907 }
03908
03909 tmp += "<br>";
03910 tmp += tooltipFormatAttendees( mCalendar, incidence );
03911
03912 int categoryCount = incidence->categories().count();
03913 if ( categoryCount > 0 ) {
03914 tmp += "<br>";
03915 tmp += "<i>" + i18n( "Category:", "%n Categories:", categoryCount ) + "</i>" + " ";
03916 tmp += incidence->categories().join( ", " );
03917 }
03918
03919 tmp += "</qt>";
03920 return tmp;
03921 }
03922
03923 QString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
03924 {
03925 return toolTipStr( 0, incidence, QDate(), richText );
03926 }
03927
03928 QString IncidenceFormatter::toolTipStr( Calendar *calendar,
03929 IncidenceBase *incidence,
03930 const QDate &date,
03931 bool richText )
03932 {
03933 ToolTipVisitor v;
03934 if ( v.act( calendar, incidence, date, richText ) ) {
03935 return v.result();
03936 } else {
03937 return QString::null;
03938 }
03939 }
03940
03941
03942
03943
03944
03945 class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
03946 {
03947 public:
03948 MailBodyVisitor() : mResult( "" ) {}
03949
03950 bool act( IncidenceBase *incidence )
03951 {
03952 mResult = "";
03953 return incidence ? incidence->accept( *this ) : false;
03954 }
03955 QString result() const { return mResult; }
03956
03957 protected:
03958 bool visit( Event *event );
03959 bool visit( Todo *todo );
03960 bool visit( Journal *journal );
03961 bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
03962 protected:
03963 QString mResult;
03964 };
03965
03966
03967 static QString mailBodyIncidence( Incidence *incidence )
03968 {
03969 QString body;
03970 if ( !incidence->summary().isEmpty() ) {
03971 body += i18n("Summary: %1\n").arg( incidence->summary() );
03972 }
03973 if ( !incidence->organizer().isEmpty() ) {
03974 body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
03975 }
03976 if ( !incidence->location().isEmpty() ) {
03977 body += i18n("Location: %1\n").arg( incidence->location() );
03978 }
03979 return body;
03980 }
03981
03982 bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
03983 {
03984 QString recurrence[]= {i18n("no recurrence", "None"),
03985 i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
03986 i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
03987 i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
03988
03989 mResult = mailBodyIncidence( event );
03990 mResult += i18n("Start Date: %1\n").
03991 arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
03992 if ( !event->doesFloat() ) {
03993 mResult += i18n("Start Time: %1\n").
03994 arg( IncidenceFormatter::timeToString( event->dtStart(), true ) );
03995 }
03996 if ( event->dtStart() != event->dtEnd() ) {
03997 mResult += i18n("End Date: %1\n").
03998 arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
03999 }
04000 if ( !event->doesFloat() ) {
04001 mResult += i18n("End Time: %1\n").
04002 arg( IncidenceFormatter::timeToString( event->dtEnd(), true ) );
04003 }
04004 if ( event->doesRecur() ) {
04005 Recurrence *recur = event->recurrence();
04006
04007 mResult += i18n("Recurs: %1\n")
04008 .arg( recurrence[ recur->recurrenceType() ] );
04009 mResult += i18n("Frequency: %1\n")
04010 .arg( event->recurrence()->frequency() );
04011
04012 if ( recur->duration() > 0 ) {
04013 mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
04014 mResult += '\n';
04015 } else {
04016 if ( recur->duration() != -1 ) {
04017
04018 QString endstr;
04019 if ( event->doesFloat() ) {
04020 endstr = KGlobal::locale()->formatDate( recur->endDate() );
04021 } else {
04022 endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
04023 }
04024 mResult += i18n("Repeat until: %1\n").arg( endstr );
04025 } else {
04026 mResult += i18n("Repeats forever\n");
04027 }
04028 }
04029 }
04030 QString details = event->description();
04031 if ( !details.isEmpty() ) {
04032 mResult += i18n("Details:\n%1\n").arg( details );
04033 }
04034 return !mResult.isEmpty();
04035 }
04036
04037 bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
04038 {
04039 mResult = mailBodyIncidence( todo );
04040
04041 if ( todo->hasStartDate() ) {
04042 mResult += i18n("Start Date: %1\n").
04043 arg( IncidenceFormatter::dateToString( todo->dtStart( false ), true ) );
04044 if ( !todo->doesFloat() ) {
04045 mResult += i18n("Start Time: %1\n").
04046 arg( IncidenceFormatter::timeToString( todo->dtStart( false ),true ) );
04047 }
04048 }
04049 if ( todo->hasDueDate() ) {
04050 mResult += i18n("Due Date: %1\n").
04051 arg( IncidenceFormatter::dateToString( todo->dtDue(), true ) );
04052 if ( !todo->doesFloat() ) {
04053 mResult += i18n("Due Time: %1\n").
04054 arg( IncidenceFormatter::timeToString( todo->dtDue(), true ) );
04055 }
04056 }
04057 QString details = todo->description();
04058 if ( !details.isEmpty() ) {
04059 mResult += i18n("Details:\n%1\n").arg( details );
04060 }
04061 return !mResult.isEmpty();
04062 }
04063
04064 bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
04065 {
04066 mResult = mailBodyIncidence( journal );
04067 mResult += i18n("Date: %1\n").
04068 arg( IncidenceFormatter::dateToString( journal->dtStart(), true ) );
04069 if ( !journal->doesFloat() ) {
04070 mResult += i18n("Time: %1\n").
04071 arg( IncidenceFormatter::timeToString( journal->dtStart(), true ) );
04072 }
04073 if ( !journal->description().isEmpty() )
04074 mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
04075 return !mResult.isEmpty();
04076 }
04077
04078
04079
04080 QString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
04081 {
04082 if ( !incidence )
04083 return QString::null;
04084
04085 MailBodyVisitor v;
04086 if ( v.act( incidence ) ) {
04087 return v.result();
04088 }
04089 return QString::null;
04090 }
04091
04092 static QString recurEnd( Incidence *incidence )
04093 {
04094 QString endstr;
04095 if ( incidence->doesFloat() ) {
04096 endstr = KGlobal::locale()->formatDate( incidence->recurrence()->endDate() );
04097 } else {
04098 endstr = KGlobal::locale()->formatDateTime( incidence->recurrence()->endDateTime() );
04099 }
04100 return endstr;
04101 }
04102
04103
04104
04105
04106 QString IncidenceFormatter::recurrenceString( Incidence *incidence )
04107 {
04108 if ( !incidence->doesRecur() ) {
04109 return i18n( "No recurrence" );
04110 }
04111 QStringList dayList;
04112 dayList.append( i18n( "31st Last" ) );
04113 dayList.append( i18n( "30th Last" ) );
04114 dayList.append( i18n( "29th Last" ) );
04115 dayList.append( i18n( "28th Last" ) );
04116 dayList.append( i18n( "27th Last" ) );
04117 dayList.append( i18n( "26th Last" ) );
04118 dayList.append( i18n( "25th Last" ) );
04119 dayList.append( i18n( "24th Last" ) );
04120 dayList.append( i18n( "23rd Last" ) );
04121 dayList.append( i18n( "22nd Last" ) );
04122 dayList.append( i18n( "21st Last" ) );
04123 dayList.append( i18n( "20th Last" ) );
04124 dayList.append( i18n( "19th Last" ) );
04125 dayList.append( i18n( "18th Last" ) );
04126 dayList.append( i18n( "17th Last" ) );
04127 dayList.append( i18n( "16th Last" ) );
04128 dayList.append( i18n( "15th Last" ) );
04129 dayList.append( i18n( "14th Last" ) );
04130 dayList.append( i18n( "13th Last" ) );
04131 dayList.append( i18n( "12th Last" ) );
04132 dayList.append( i18n( "11th Last" ) );
04133 dayList.append( i18n( "10th Last" ) );
04134 dayList.append( i18n( "9th Last" ) );
04135 dayList.append( i18n( "8th Last" ) );
04136 dayList.append( i18n( "7th Last" ) );
04137 dayList.append( i18n( "6th Last" ) );
04138 dayList.append( i18n( "5th Last" ) );
04139 dayList.append( i18n( "4th Last" ) );
04140 dayList.append( i18n( "3rd Last" ) );
04141 dayList.append( i18n( "2nd Last" ) );
04142 dayList.append( i18n( "last day of the month", "Last" ) );
04143 dayList.append( i18n( "unknown day of the month", "unknown" ) );
04144 dayList.append( i18n( "1st" ) );
04145 dayList.append( i18n( "2nd" ) );
04146 dayList.append( i18n( "3rd" ) );
04147 dayList.append( i18n( "4th" ) );
04148 dayList.append( i18n( "5th" ) );
04149 dayList.append( i18n( "6th" ) );
04150 dayList.append( i18n( "7th" ) );
04151 dayList.append( i18n( "8th" ) );
04152 dayList.append( i18n( "9th" ) );
04153 dayList.append( i18n( "10th" ) );
04154 dayList.append( i18n( "11th" ) );
04155 dayList.append( i18n( "12th" ) );
04156 dayList.append( i18n( "13th" ) );
04157 dayList.append( i18n( "14th" ) );
04158 dayList.append( i18n( "15th" ) );
04159 dayList.append( i18n( "16th" ) );
04160 dayList.append( i18n( "17th" ) );
04161 dayList.append( i18n( "18th" ) );
04162 dayList.append( i18n( "19th" ) );
04163 dayList.append( i18n( "20th" ) );
04164 dayList.append( i18n( "21st" ) );
04165 dayList.append( i18n( "22nd" ) );
04166 dayList.append( i18n( "23rd" ) );
04167 dayList.append( i18n( "24th" ) );
04168 dayList.append( i18n( "25th" ) );
04169 dayList.append( i18n( "26th" ) );
04170 dayList.append( i18n( "27th" ) );
04171 dayList.append( i18n( "28th" ) );
04172 dayList.append( i18n( "29th" ) );
04173 dayList.append( i18n( "30th" ) );
04174 dayList.append( i18n( "31st" ) );
04175
04176 int weekStart = KGlobal::locale()->weekStartDay();
04177 QString dayNames;
04178
04179 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
04180
04181 Recurrence *recur = incidence->recurrence();
04182
04183 QString recurStr;
04184 switch ( recur->recurrenceType() ) {
04185 case Recurrence::rNone:
04186 return i18n( "No recurrence" );
04187
04188 case Recurrence::rMinutely:
04189 recurStr = i18n( "Recurs every minute", "Recurs every %n minutes", recur->frequency() );
04190 if ( recur->duration() != -1 ) {
04191 recurStr = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
04192 if ( recur->duration() > 0 ) {
04193 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04194 }
04195 }
04196 break;
04197
04198 case Recurrence::rHourly:
04199 recurStr = i18n( "Recurs hourly", "Recurs every %n hours", recur->frequency() );
04200 if ( recur->duration() != -1 ) {
04201 recurStr = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
04202 if ( recur->duration() > 0 ) {
04203 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04204 }
04205 }
04206 break;
04207
04208 case Recurrence::rDaily:
04209 recurStr = i18n( "Recurs daily", "Recurs every %n days", recur->frequency() );
04210 if ( recur->duration() != -1 ) {
04211 recurStr = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
04212 if ( recur->duration() > 0 ) {
04213 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04214 }
04215 }
04216 break;
04217
04218 case Recurrence::rWeekly:
04219 {
04220 recurStr = i18n( "Recurs weekly", "Recurs every %n weeks", recur->frequency() );
04221
04222 bool addSpace = false;
04223 for ( int i = 0; i < 7; ++i ) {
04224 if ( recur->days().testBit( ( i + weekStart + 6 ) % 7 ) ) {
04225 if ( addSpace ) {
04226 dayNames.append( i18n( "separator for list of days", ", " ) );
04227 }
04228 dayNames.append( calSys->weekDayName( ( ( i + weekStart + 6 ) % 7 ) + 1, true ) );
04229 addSpace = true;
04230 }
04231 }
04232 if ( dayNames.isEmpty() ) {
04233 dayNames = i18n( "Recurs weekly on no days", "no days" );
04234 }
04235 if ( recur->duration() != -1 ) {
04236 recurStr = i18n( "%1 on %2 until %3" ).
04237 arg( recurStr ).arg( dayNames ).arg( recurEnd( incidence ) );
04238 if ( recur->duration() > 0 ) {
04239 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04240 }
04241 } else {
04242 recurStr = i18n( "%1 on %2" ).arg( recurStr ).arg( dayNames );
04243 }
04244 break;
04245 }
04246
04247 case Recurrence::rMonthlyPos:
04248 {
04249 recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
04250
04251 if ( !recur->monthPositions().isEmpty() ) {
04252 KCal::RecurrenceRule::WDayPos rule = recur->monthPositions()[0];
04253 if ( recur->duration() != -1 ) {
04254 recurStr = i18n( "%1 on the %2 %3 until %4" ).
04255 arg( recurStr ).
04256 arg( dayList[rule.pos() + 31] ).
04257 arg( calSys->weekDayName( rule.day(), false ) ).
04258 arg( recurEnd( incidence ) );
04259 if ( recur->duration() > 0 ) {
04260 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04261 }
04262 } else {
04263 recurStr = i18n( "%1 on the %2 %3" ).
04264 arg( recurStr ).
04265 arg( dayList[rule.pos() + 31] ).
04266 arg( calSys->weekDayName( rule.day(), false ) );
04267 }
04268 }
04269 break;
04270 }
04271
04272 case Recurrence::rMonthlyDay:
04273 {
04274 recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
04275
04276 if ( !recur->monthDays().isEmpty() ) {
04277 int days = recur->monthDays()[0];
04278 if ( recur->duration() != -1 ) {
04279 recurStr = i18n( "%1 on the %2 day until %3" ).
04280 arg( recurStr ).
04281 arg( dayList[days + 31] ).
04282 arg( recurEnd( incidence ) );
04283 if ( recur->duration() > 0 ) {
04284 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04285 }
04286 } else {
04287 recurStr = i18n( "%1 on the %2 day" ).arg( recurStr ).arg( dayList[days + 31] );
04288 }
04289 }
04290 break;
04291 }
04292 case Recurrence::rYearlyMonth:
04293 {
04294 recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
04295
04296 if ( recur->duration() != -1 ) {
04297 if ( !recur->yearDates().isEmpty() ) {
04298 recurStr = i18n( "%1 on %2 %3 until %4" ).
04299 arg( recurStr ).
04300 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
04301 arg( dayList[ recur->yearDates()[0] + 31 ] ).
04302 arg( recurEnd( incidence ) );
04303 if ( recur->duration() > 0 ) {
04304 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04305 }
04306 }
04307 } else {
04308 if ( !recur->yearDates().isEmpty() ) {
04309 recurStr = i18n( "%1 on %2 %3" ).
04310 arg( recurStr ).
04311 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
04312 arg( dayList[ recur->yearDates()[0] + 31 ] );
04313 } else {
04314 if ( !recur->yearMonths().isEmpty() ) {
04315 recurStr = i18n( "Recurs yearly on %1 %2" ).
04316 arg( calSys->monthName( recur->yearMonths()[0],
04317 recur->startDate().year() ) ).
04318 arg( dayList[ recur->startDate().day() + 31 ] );
04319 } else {
04320 recurStr = i18n( "Recurs yearly on %1 %2" ).
04321 arg( calSys->monthName( recur->startDate().month(),
04322 recur->startDate().year() ) ).
04323 arg( dayList[ recur->startDate().day() + 31 ] );
04324 }
04325 }
04326 }
04327 break;
04328 }
04329 case Recurrence::rYearlyDay:
04330 {
04331 recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
04332 if ( !recur->yearDays().isEmpty() ) {
04333 if ( recur->duration() != -1 ) {
04334 recurStr = i18n( "%1 on day %2 until %3" ).
04335 arg( recurStr ).
04336 arg( recur->yearDays()[0] ).
04337 arg( recurEnd( incidence ) );
04338 if ( recur->duration() > 0 ) {
04339 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04340 }
04341 } else {
04342 recurStr = i18n( "%1 on day %2" ).arg( recurStr ).arg( recur->yearDays()[0] );
04343 }
04344 }
04345 break;
04346 }
04347 case Recurrence::rYearlyPos:
04348 {
04349 recurStr = i18n( "Every year", "Every %n years", recur->frequency() );
04350 if ( !recur->yearPositions().isEmpty() && !recur->yearMonths().isEmpty() ) {
04351 KCal::RecurrenceRule::WDayPos rule = recur->yearPositions()[0];
04352 if ( recur->duration() != -1 ) {
04353 recurStr = i18n( "%1 on the %2 %3 of %4 until %5" ).
04354 arg( recurStr ).
04355 arg( dayList[rule.pos() + 31] ).
04356 arg( calSys->weekDayName( rule.day(), false ) ).
04357 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
04358 arg( recurEnd( incidence ) );
04359 if ( recur->duration() > 0 ) {
04360 recurStr += i18n( " (%1 occurrences)" ).arg( recur->duration() );
04361 }
04362 } else {
04363 recurStr = i18n( "%1 on the %2 %3 of %4" ).
04364 arg( recurStr ).
04365 arg( dayList[rule.pos() + 31] ).
04366 arg( calSys->weekDayName( rule.day(), false ) ).
04367 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) );
04368 }
04369 }
04370 break;
04371 }
04372 }
04373
04374 if ( recurStr.isEmpty() ) {
04375 recurStr = i18n( "Incidence recurs" );
04376 }
04377
04378 DateTimeList l = recur->exDateTimes();
04379 DateTimeList::ConstIterator il;
04380 QStringList exStr;
04381 for ( il = l.constBegin(); il != l.constEnd(); ++il ) {
04382 switch ( recur->recurrenceType() ) {
04383 case Recurrence::rMinutely:
04384 exStr << i18n( "minute %1" ).arg( (*il).time().minute() );
04385 break;
04386 case Recurrence::rHourly:
04387 exStr << KGlobal::locale()->formatTime( (*il).time() );
04388 break;
04389 case Recurrence::rDaily:
04390 exStr << KGlobal::locale()->formatDate( (*il).date(), true );
04391 break;
04392 case Recurrence::rWeekly:
04393 exStr << calSys->weekDayName( (*il).date(), true );
04394 break;
04395 case Recurrence::rMonthlyPos:
04396 exStr << KGlobal::locale()->formatDate( (*il).date(), true );
04397 break;
04398 case Recurrence::rMonthlyDay:
04399 exStr << KGlobal::locale()->formatDate( (*il).date(), true );
04400 break;
04401 case Recurrence::rYearlyMonth:
04402 exStr << calSys->monthName( (*il).date(), false );
04403 break;
04404 case Recurrence::rYearlyDay:
04405 exStr << KGlobal::locale()->formatDate( (*il).date(), true );
04406 break;
04407 case Recurrence::rYearlyPos:
04408 exStr << KGlobal::locale()->formatDate( (*il).date(), true );
04409 break;
04410 }
04411 }
04412
04413 if ( !exStr.isEmpty() ) {
04414 recurStr = i18n( "%1 (excluding %2)" ).arg( recurStr, exStr.join( "," ) );
04415 }
04416
04417 return recurStr;
04418 }
04419
04420 QString IncidenceFormatter::timeToString( const QDateTime &date, bool shortfmt )
04421 {
04422 return KGlobal::locale()->formatTime( date.time(), !shortfmt );
04423 }
04424
04425 QString IncidenceFormatter::dateToString( const QDateTime &date, bool shortfmt )
04426 {
04427 return
04428 KGlobal::locale()->formatDate( date.date(), shortfmt );
04429 }
04430
04431 QString IncidenceFormatter::dateTimeToString( const QDateTime &date,
04432 bool allDay, bool shortfmt )
04433 {
04434 if ( allDay ) {
04435 return dateToString( date, shortfmt );
04436 }
04437
04438 return KGlobal::locale()->formatDateTime( date, shortfmt );
04439 }
04440
04441 QString IncidenceFormatter::resourceString( Calendar *calendar, Incidence *incidence )
04442 {
04443 if ( !calendar || !incidence ) {
04444 return QString::null;
04445 }
04446
04447 CalendarResources *calendarResource = dynamic_cast<CalendarResources*>( calendar );
04448 if ( !calendarResource ) {
04449 return QString::null;
04450 }
04451
04452 ResourceCalendar *resourceCalendar = calendarResource->resource( incidence );
04453 if ( resourceCalendar ) {
04454 if ( !resourceCalendar->subresources().isEmpty() ) {
04455 QString subRes = resourceCalendar->subresourceIdentifier( incidence );
04456 if ( subRes.isEmpty() ) {
04457 return resourceCalendar->resourceName();
04458 } else {
04459 return resourceCalendar->labelForSubresource( subRes );
04460 }
04461 }
04462 return resourceCalendar->resourceName();
04463 }
04464
04465 return QString::null;
04466 }
04467
04468 static QString secs2Duration( int secs )
04469 {
04470 QString tmp;
04471 int days = secs / 86400;
04472 if ( days > 0 ) {
04473 tmp += i18n( "1 day", "%n days", days );
04474 tmp += ' ';
04475 secs -= ( days * 86400 );
04476 }
04477 int hours = secs / 3600;
04478 if ( hours > 0 ) {
04479 tmp += i18n( "1 hour", "%n hours", hours );
04480 tmp += ' ';
04481 secs -= ( hours * 3600 );
04482 }
04483 int mins = secs / 60;
04484 if ( mins > 0 ) {
04485 tmp += i18n( "1 minute", "%n minutes", mins );
04486 }
04487 return tmp;
04488 }
04489
04490 QString IncidenceFormatter::durationString( Incidence *incidence )
04491 {
04492 QString tmp;
04493 if ( incidence->type() == "Event" ) {
04494 Event *event = static_cast<Event *>( incidence );
04495 if ( event->hasEndDate() ) {
04496 if ( !event->doesFloat() ) {
04497 tmp = secs2Duration( event->dtStart().secsTo( event->dtEnd() ) );
04498 } else {
04499 tmp = i18n( "1 day", "%n days",
04500 event->dtStart().date().daysTo( event->dtEnd().date() ) + 1 );
04501 }
04502 } else {
04503 tmp = i18n( "forever" );
04504 }
04505 } else if ( incidence->type() == "Todo" ) {
04506 Todo *todo = static_cast<Todo *>( incidence );
04507 if ( todo->hasDueDate() ) {
04508 if ( todo->hasStartDate() ) {
04509 if ( !todo->doesFloat() ) {
04510 tmp = secs2Duration( todo->dtStart().secsTo( todo->dtDue() ) );
04511 } else {
04512 tmp = i18n( "1 day", "%n days",
04513 todo->dtStart().date().daysTo( todo->dtDue().date() ) + 1 );
04514 }
04515 }
04516 }
04517 }
04518 return tmp;
04519 }
04520
04521 QStringList IncidenceFormatter::reminderStringList( Incidence *incidence, bool shortfmt )
04522 {
04523
04524 Q_UNUSED( shortfmt );
04525
04526 QStringList reminderStringList;
04527
04528 if ( incidence ) {
04529 Alarm::List alarms = incidence->alarms();
04530 Alarm::List::ConstIterator it;
04531 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
04532 Alarm *alarm = *it;
04533 int offset = 0;
04534 QString remStr, atStr, offsetStr;
04535 if ( alarm->hasTime() ) {
04536 offset = 0;
04537 if ( alarm->time().isValid() ) {
04538 atStr = KGlobal::locale()->formatDateTime( alarm->time() );
04539 }
04540 } else if ( alarm->hasStartOffset() ) {
04541 offset = alarm->startOffset().asSeconds();
04542 if ( offset < 0 ) {
04543 offset = -offset;
04544 offsetStr = i18n( "N days/hours/minutes before the start datetime",
04545 "%1 before the start" );
04546 } else if ( offset > 0 ) {
04547 offsetStr = i18n( "N days/hours/minutes after the start datetime",
04548 "%1 after the start" );
04549 } else {
04550 if ( incidence->dtStart().isValid() ) {
04551 atStr = KGlobal::locale()->formatDateTime( incidence->dtStart() );
04552 }
04553 }
04554 } else if ( alarm->hasEndOffset() ) {
04555 offset = alarm->endOffset().asSeconds();
04556 if ( offset < 0 ) {
04557 offset = -offset;
04558 if ( incidence->type() == "Todo" ) {
04559 offsetStr = i18n( "N days/hours/minutes before the due datetime",
04560 "%1 before the to-do is due" );
04561 } else {
04562 offsetStr = i18n( "N days/hours/minutes before the end datetime",
04563 "%1 before the end" );
04564 }
04565 } else if ( offset > 0 ) {
04566 if ( incidence->type() == "Todo" ) {
04567 offsetStr = i18n( "N days/hours/minutes after the due datetime",
04568 "%1 after the to-do is due" );
04569 } else {
04570 offsetStr = i18n( "N days/hours/minutes after the end datetime",
04571 "%1 after the end" );
04572 }
04573 } else {
04574 if ( incidence->type() == "Todo" ) {
04575 Todo *t = static_cast<Todo *>( incidence );
04576 if ( t->dtDue().isValid() ) {
04577 atStr = KGlobal::locale()->formatDateTime( t->dtDue() );
04578 }
04579 } else {
04580 Event *e = static_cast<Event *>( incidence );
04581 if ( e->dtEnd().isValid() ) {
04582 atStr = KGlobal::locale()->formatDateTime( e->dtEnd() );
04583 }
04584 }
04585 }
04586 }
04587 if ( offset == 0 ) {
04588 if ( !atStr.isEmpty() ) {
04589 remStr = i18n( "reminder occurs at datetime", "at %1" ).arg( atStr );
04590 }
04591 } else {
04592 remStr = offsetStr.arg( secs2Duration( offset ) );
04593 }
04594
04595 if ( alarm->repeatCount() > 0 ) {
04596 QString countStr = i18n( "repeats once", "repeats %n times", alarm->repeatCount() );
04597 QString intervalStr = i18n( "interval is N days/hours/minutes", "interval is %1" ).
04598 arg( secs2Duration( alarm->snoozeTime().asSeconds() ) );
04599 QString repeatStr = i18n( "(repeat string, interval string)", "(%1, %2)" ).
04600 arg( countStr, intervalStr );
04601 remStr = remStr + ' ' + repeatStr;
04602
04603 }
04604 reminderStringList << remStr;
04605 }
04606 }
04607
04608 return reminderStringList;
04609 }