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