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