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