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