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