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