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