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