00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "incidenceformatter.h"
00024
00025 #include <libkcal/attachment.h>
00026 #include <libkcal/event.h>
00027 #include <libkcal/todo.h>
00028 #include <libkcal/journal.h>
00029 #include <libkcal/calendar.h>
00030 #include <libkcal/calendarlocal.h>
00031 #include <libkcal/icalformat.h>
00032 #include <libkcal/freebusy.h>
00033
00034 #include <libemailfunctions/email.h>
00035
00036 #include <ktnef/ktnefparser.h>
00037 #include <ktnef/ktnefmessage.h>
00038 #include <ktnef/ktnefdefs.h>
00039 #include <kabc/phonenumber.h>
00040 #include <kabc/vcardconverter.h>
00041 #include <kabc/stdaddressbook.h>
00042
00043 #include <kapplication.h>
00044
00045
00046 #include <klocale.h>
00047 #include <kglobal.h>
00048 #include <kiconloader.h>
00049
00050 #include <qbuffer.h>
00051 #include <qstylesheet.h>
00052 #include <qdatetime.h>
00053
00054 #include <time.h>
00055
00056
00057 using namespace KCal;
00058
00059
00060
00061
00062
00063
00064 static QString eventViewerAddLink( const QString &ref, const QString &text,
00065 bool newline = true )
00066 {
00067 QString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
00068 if ( newline ) tmpStr += "\n";
00069 return tmpStr;
00070 }
00071
00072 static QString eventViewerAddTag( const QString & tag, const QString & text )
00073 {
00074 int numLineBreaks = text.contains( "\n" );
00075 QString str = "<" + tag + ">";
00076 QString tmpText = text;
00077 QString tmpStr = str;
00078 if( numLineBreaks >= 0 ) {
00079 if ( numLineBreaks > 0) {
00080 int pos = 0;
00081 QString tmp;
00082 for( int i = 0; i <= numLineBreaks; i++ ) {
00083 pos = tmpText.find( "\n" );
00084 tmp = tmpText.left( pos );
00085 tmpText = tmpText.right( tmpText.length() - pos - 1 );
00086 tmpStr += tmp + "<br>";
00087 }
00088 } else {
00089 tmpStr += tmpText;
00090 }
00091 }
00092 tmpStr += "</" + tag + ">";
00093 return tmpStr;
00094 }
00095
00096 static QString linkPerson( const QString& email, QString name, QString uid )
00097 {
00098
00099
00100 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
00101 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00102 KABC::Addressee::List addressList = add_book->findByEmail( email );
00103 KABC::Addressee o = addressList.first();
00104 if ( !o.isEmpty() && addressList.size() < 2 ) {
00105 if ( name.isEmpty() )
00106
00107 name = o.formattedName();
00108 uid = o.uid();
00109 } else
00110
00111 uid = QString::null;
00112 }
00113 kdDebug(5850) << "formatAttendees: uid = " << uid << endl;
00114
00115
00116 QString tmpString = "<li>";
00117 if ( !uid.isEmpty() ) {
00118
00119 if ( name.isEmpty() )
00120
00121 tmpString += eventViewerAddLink( "uid:" + uid, email );
00122 else
00123 tmpString += eventViewerAddLink( "uid:" + uid, name );
00124 } else {
00125
00126 tmpString += ( name.isEmpty() ? email : name );
00127 }
00128 tmpString += '\n';
00129
00130
00131 if ( !email.isEmpty() ) {
00132 KCal::Person person( name, email );
00133 KURL mailto;
00134 mailto.setProtocol( "mailto" );
00135 mailto.setPath( person.fullName() );
00136 tmpString += eventViewerAddLink( mailto.url(), QString::null );
00137 }
00138 tmpString += "</li>\n";
00139
00140 return tmpString;
00141 }
00142
00143 static QString eventViewerFormatAttendees( Incidence *event )
00144 {
00145 QString tmpStr;
00146 Attendee::List attendees = event->attendees();
00147 if ( attendees.count() ) {
00148
00149
00150 tmpStr += eventViewerAddTag( "i", i18n("Organizer") );
00151 tmpStr += "<ul>";
00152 tmpStr += linkPerson( event->organizer().email(),
00153 event->organizer().name(), QString::null );
00154 tmpStr += "</ul>";
00155
00156
00157 tmpStr += eventViewerAddTag( "i", i18n("Attendees") );
00158 tmpStr += "<ul>";
00159 Attendee::List::ConstIterator it;
00160 for( it = attendees.begin(); it != attendees.end(); ++it ) {
00161 Attendee *a = *it;
00162 tmpStr += linkPerson( a->email(), a->name(), a->uid() );
00163 if ( !a->delegator().isEmpty() ) {
00164 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
00165 }
00166 if ( !a->delegate().isEmpty() ) {
00167 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
00168 }
00169 }
00170 tmpStr += "</ul>";
00171 }
00172 return tmpStr;
00173 }
00174
00175 static QString eventViewerFormatAttachments( Incidence *i )
00176 {
00177 QString tmpStr;
00178 Attachment::List as = i->attachments();
00179 if ( as.count() > 0 ) {
00180 Attachment::List::ConstIterator it;
00181 for( it = as.begin(); it != as.end(); ++it ) {
00182 if ( (*it)->isUri() ) {
00183 QString name;
00184 if ( (*it)->uri().startsWith( "kmail:" ) )
00185 name = i18n( "Show mail" );
00186 else
00187 name = (*it)->uri();
00188 tmpStr += eventViewerAddLink( (*it)->uri(), name );
00189 tmpStr += "<br>";
00190 }
00191 }
00192 }
00193 return tmpStr;
00194 }
00195
00196
00197
00198
00199
00200 static QString eventViewerFormatBirthday( Event *event )
00201 {
00202 if ( !event) return QString::null;
00203 if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) return QString::null;
00204
00205 QString uid = event->customProperty("KABC","UID-1");
00206 QString name = event->customProperty("KABC","NAME-1");
00207 QString email= event->customProperty("KABC","EMAIL-1");
00208
00209 QString tmpString = "<ul>";
00210 tmpString += linkPerson( email, name, uid );
00211
00212 if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
00213 uid = event->customProperty("KABC","UID-2");
00214 name = event->customProperty("KABC","NAME-2");
00215 email= event->customProperty("KABC","EMAIL-2");
00216 tmpString += linkPerson( email, name, uid );
00217 }
00218
00219 tmpString += "</ul>";
00220 return tmpString;
00221 }
00222
00223 static QString eventViewerFormatHeader( Incidence *incidence )
00224 {
00225 QString tmpStr = "<table><tr>";
00226
00227
00228 {
00229 tmpStr += "<td>";
00230
00231 if ( incidence->type() == "Event" ) {
00232 tmpStr += "<img src=\"" +
00233 KGlobal::iconLoader()->iconPath( "appointment", KIcon::Small ) +
00234 "\">";
00235 }
00236 if ( incidence->type() == "Todo" ) {
00237 tmpStr += "<img src=\"" +
00238 KGlobal::iconLoader()->iconPath( "todo", KIcon::Small ) +
00239 "\">";
00240 }
00241 if ( incidence->type() == "Journal" ) {
00242 tmpStr += "<img src=\"" +
00243 KGlobal::iconLoader()->iconPath( "journal", KIcon::Small ) +
00244 "\">";
00245 }
00246 if ( incidence->isAlarmEnabled() ) {
00247 tmpStr += "<img src=\"" +
00248 KGlobal::iconLoader()->iconPath( "bell", KIcon::Small ) +
00249 "\">";
00250 }
00251 if ( incidence->doesRecur() ) {
00252 tmpStr += "<img src=\"" +
00253 KGlobal::iconLoader()->iconPath( "recur", KIcon::Small ) +
00254 "\">";
00255 }
00256 if ( incidence->isReadOnly() ) {
00257 tmpStr += "<img src=\"" +
00258 KGlobal::iconLoader()->iconPath( "readonlyevent", KIcon::Small ) +
00259 "\">";
00260 }
00261
00262 tmpStr += "</td>";
00263 }
00264
00265 tmpStr += "<td>"
00266 + eventViewerAddTag( "u",
00267 eventViewerAddTag( "b", incidence->summary() ) )
00268 + "</td>";
00269 tmpStr += "</tr></table><br>";
00270
00271 return tmpStr;
00272 }
00273
00274 static QString eventViewerFormatEvent( Event *event )
00275 {
00276 if ( !event ) return QString::null;
00277 QString tmpStr = eventViewerFormatHeader( event );
00278
00279 tmpStr += "<table>";
00280
00281 tmpStr += "<tr>";
00282 if ( event->doesFloat() ) {
00283 if ( event->isMultiDay() ) {
00284 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00285 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00286 .arg( event->dtStartDateStr() )
00287 .arg( event->dtEndDateStr() ) + "</td>";
00288 } else {
00289 tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
00290 tmpStr += "<td>" + i18n("date as string","%1").arg( event->dtStartDateStr() ) + "</td>";
00291 }
00292 } else {
00293 if ( event->isMultiDay() ) {
00294 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00295 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00296 .arg( event->dtStartStr() )
00297 .arg( event->dtEndStr() ) + "</td>";
00298 } else {
00299 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00300 if ( event->hasEndDate() && event->dtStart() != event->dtEnd()) {
00301 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00302 .arg( event->dtStartTimeStr() )
00303 .arg( event->dtEndTimeStr() ) + "</td>";
00304 } else {
00305 tmpStr += "<td>" + event->dtStartTimeStr() + "</td>";
00306 }
00307 tmpStr += "</tr><tr>";
00308 tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
00309 tmpStr += "<td>" + i18n("date as string","%1")
00310 .arg( event->dtStartDateStr() ) + "</td>";
00311 }
00312 }
00313 tmpStr += "</tr>";
00314
00315 if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
00316 tmpStr += "<tr>";
00317 tmpStr += "<td align=\"right\"><b>" + i18n( "Birthday" ) + "</b></td>";
00318 tmpStr += "<td>" + eventViewerFormatBirthday( event ) + "</td>";
00319 tmpStr += "</tr>";
00320 tmpStr += "</table>";
00321 return tmpStr;
00322 }
00323
00324 if ( !event->description().isEmpty() ) {
00325 tmpStr += "<tr>";
00326 tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
00327 tmpStr += "<td>" + eventViewerAddTag( "p", event->description() ) + "</td>";
00328 tmpStr += "</tr>";
00329 }
00330
00331 if ( !event->location().isEmpty() ) {
00332 tmpStr += "<tr>";
00333 tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
00334 tmpStr += "<td>" + event->location() + "</td>";
00335 tmpStr += "</tr>";
00336 }
00337
00338 if ( event->categories().count() > 0 ) {
00339 tmpStr += "<tr>";
00340 tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", event->categories().count() )+ "</b></td>";
00341 tmpStr += "<td>" + event->categoriesStr() + "</td>";
00342 tmpStr += "</tr>";
00343 }
00344
00345 if ( event->doesRecur() ) {
00346 QDateTime dt =
00347 event->recurrence()->getNextDateTime( QDateTime::currentDateTime() );
00348 tmpStr += "<tr>";
00349 tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
00350 if ( !event->doesFloat() ) {
00351 tmpStr += "<td>" +
00352 KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
00353 } else {
00354 tmpStr += "<td>" +
00355 KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
00356 }
00357 tmpStr += "</tr>";
00358 }
00359
00360 int attendeeCount = event->attendees().count();
00361 if ( attendeeCount > 0 ) {
00362 tmpStr += "<tr><td colspan=\"2\">";
00363 tmpStr += eventViewerFormatAttendees( event );
00364 tmpStr += "</td></tr>";
00365 }
00366
00367 int attachmentCount = event->attachments().count();
00368 if ( attachmentCount > 0 ) {
00369 tmpStr += "<tr>";
00370 tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
00371 tmpStr += "<td>" + eventViewerFormatAttachments( event ) + "</td>";
00372 tmpStr += "</tr>";
00373 }
00374
00375 tmpStr += "</table>";
00376 tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
00377 KGlobal::locale()->formatDateTime( event->created() , true ) ) + "</em>";
00378 return tmpStr;
00379 }
00380
00381 static QString eventViewerFormatTodo( Todo *todo )
00382 {
00383 if ( !todo ) return QString::null;
00384 QString tmpStr = eventViewerFormatHeader( todo );
00385
00386 tmpStr += "<table>";
00387
00388 if ( todo->hasDueDate() ) {
00389 tmpStr += "<tr>";
00390 tmpStr += "<td align=\"right\"><b>" + i18n( "Due on" ) + "</b></td>";
00391 if ( !todo->doesFloat() ) {
00392 tmpStr += "<td>" +
00393 KGlobal::locale()->formatDateTime( todo->dtDue(), true ) +
00394 "</td>";
00395 } else {
00396 tmpStr += "<td>" +
00397 KGlobal::locale()->formatDate( todo->dtDue().date(), true ) +
00398 "</td>";
00399 }
00400 tmpStr += "</tr>";
00401 }
00402
00403 if ( !todo->description().isEmpty() ) {
00404 tmpStr += "<tr>";
00405 tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
00406 tmpStr += "<td>" + todo->description() + "</td>";
00407 tmpStr += "</tr>";
00408 }
00409
00410 if ( !todo->location().isEmpty() ) {
00411 tmpStr += "<tr>";
00412 tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
00413 tmpStr += "<td>" + todo->location() + "</td>";
00414 tmpStr += "</tr>";
00415 }
00416
00417 if ( todo->categories().count() > 0 ) {
00418 tmpStr += "<tr>";
00419 tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", todo->categories().count() )+ "</b></td>";
00420 tmpStr += "<td>" + todo->categoriesStr() + "</td>";
00421 tmpStr += "</tr>";
00422 }
00423
00424 tmpStr += "<tr>";
00425 tmpStr += "<td align=\"right\"><b>" + i18n( "Priority" ) + "</b></td>";
00426 if ( todo->priority() > 0 ) {
00427 tmpStr += "<td>" + QString::number( todo->priority() ) + "</td>";
00428 } else {
00429 tmpStr += "<td>" + i18n( "Unspecified" ) + "</td>";
00430 }
00431 tmpStr += "</tr>";
00432
00433 tmpStr += "<tr>";
00434 tmpStr += "<td align=\"right\"><b>" + i18n( "Completed" ) + "</b></td>";
00435 tmpStr += "<td>" + i18n( "%1 %" ).arg( todo->percentComplete() ) + "</td>";
00436 tmpStr += "</tr>";
00437
00438 if ( todo->doesRecur() ) {
00439 QDateTime dt =
00440 todo->recurrence()->getNextDateTime( QDateTime::currentDateTime() );
00441 tmpStr += "<tr>";
00442 tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
00443 if ( !todo->doesFloat() ) {
00444 tmpStr += "<td>" +
00445 KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
00446 } else {
00447 tmpStr += "<td>" +
00448 KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
00449 }
00450 tmpStr += "</tr>";
00451 }
00452
00453 int attendeeCount = todo->attendees().count();
00454 if ( attendeeCount > 0 ) {
00455 tmpStr += "<tr><td colspan=\"2\">";
00456 tmpStr += eventViewerFormatAttendees( todo );
00457 tmpStr += "</td></tr>";
00458 }
00459
00460 int attachmentCount = todo->attachments().count();
00461 if ( attachmentCount > 0 ) {
00462 tmpStr += "<tr>";
00463 tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
00464 tmpStr += "<td>" + eventViewerFormatAttachments( todo ) + "</td>";
00465 tmpStr += "</tr>";
00466 }
00467
00468 tmpStr += "</table>";
00469 tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
00470 KGlobal::locale()->formatDateTime( todo->created(), true ) ) + "</em>";
00471 return tmpStr;
00472 }
00473
00474 static QString eventViewerFormatJournal( Journal *journal )
00475 {
00476 if ( !journal ) return QString::null;
00477
00478 QString tmpStr;
00479 if ( !journal->summary().isEmpty() ) {
00480 tmpStr += eventViewerAddTag( "u",
00481 eventViewerAddTag( "b", journal->summary() ) );
00482 }
00483 tmpStr += eventViewerAddTag( "b", i18n("Journal for %1").arg( journal->dtStartDateStr( false ) ) );
00484 if ( !journal->description().isEmpty() )
00485 tmpStr += eventViewerAddTag( "p", journal->description() );
00486 return tmpStr;
00487 }
00488
00489 static QString eventViewerFormatFreeBusy( FreeBusy *fb )
00490 {
00491 if ( !fb ) return QString::null;
00492
00493 QString tmpStr =
00494 eventViewerAddTag( "u",
00495 eventViewerAddTag( "b", i18n("Free/Busy information for %1")
00496 .arg( fb->organizer().fullName() ) ) );
00497 tmpStr += eventViewerAddTag( "i", i18n("Busy times in date range %1 - %2:")
00498 .arg( KGlobal::locale()->formatDate( fb->dtStart().date(), true ) )
00499 .arg( KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) ) );
00500
00501 QValueList<Period> periods = fb->busyPeriods();
00502
00503 QString text = eventViewerAddTag( "em", eventViewerAddTag( "b", i18n("Busy:") ) );
00504 QValueList<Period>::iterator it;
00505 for ( it = periods.begin(); it != periods.end(); ++it ) {
00506 Period per = *it;
00507 if ( per.hasDuration() ) {
00508 int dur = per.duration().asSeconds();
00509 QString cont;
00510 if ( dur >= 3600 ) {
00511 cont += i18n("1 hour ", "%n hours ", dur / 3600 );
00512 dur %= 3600;
00513 }
00514 if ( dur >= 60 ) {
00515 cont += i18n("1 minute ", "%n minutes ", dur / 60);
00516 dur %= 60;
00517 }
00518 if ( dur > 0 ) {
00519 cont += i18n("1 second", "%n seconds", dur);
00520 }
00521 text += i18n("startDate for duration", "%1 for %2")
00522 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00523 .arg( cont );
00524 text += "<br>";
00525 } else {
00526 if ( per.start().date() == per.end().date() ) {
00527 text += i18n("date, fromTime - toTime ", "%1, %2 - %3")
00528 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
00529 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
00530 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
00531 } else {
00532 text += i18n("fromDateTime - toDateTime", "%1 - %2")
00533 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00534 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
00535 }
00536 text += "<br>";
00537 }
00538 }
00539 tmpStr += eventViewerAddTag( "p", text );
00540 return tmpStr;
00541 }
00542
00543 class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
00544 {
00545 public:
00546 EventViewerVisitor() { mResult = ""; }
00547 bool act( IncidenceBase *incidence ) { return incidence->accept( *this ); }
00548 QString result() const { return mResult; }
00549 protected:
00550 bool visit( Event *event )
00551 {
00552 mResult = eventViewerFormatEvent( event );
00553 return !mResult.isEmpty();
00554 }
00555 bool visit( Todo *todo )
00556 {
00557 mResult = eventViewerFormatTodo( todo );
00558 return !mResult.isEmpty();
00559 }
00560 bool visit( Journal *journal )
00561 {
00562 mResult = eventViewerFormatJournal( journal );
00563 return !mResult.isEmpty();
00564 }
00565 bool visit( FreeBusy *fb )
00566 {
00567 mResult = eventViewerFormatFreeBusy( fb );
00568 return !mResult.isEmpty();
00569 }
00570
00571 protected:
00572 QString mResult;
00573 };
00574
00575 QString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
00576 {
00577 if ( !incidence ) return QString::null;
00578 EventViewerVisitor v;
00579 if ( v.act( incidence ) ) {
00580 return v.result();
00581 } else
00582 return QString::null;
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592 static QString string2HTML( const QString& str )
00593 {
00594 return QStyleSheet::convertFromPlainText(str, QStyleSheetItem::WhiteSpaceNormal);
00595 }
00596
00597 static QString invitationRow( const QString &cell1, const QString &cell2 )
00598 {
00599 return "<tr><td>" + cell1 + "</td><td>" + cell2 + "</td></tr>\n";
00600 }
00601
00602 static QString invitationDetailsEvent( Event* event )
00603 {
00604
00605 if ( !event )
00606 return QString::null;
00607
00608 QString html;
00609 QString tmp;
00610
00611 QString sSummary = i18n( "Summary unspecified" );
00612 if ( ! event->summary().isEmpty() ) {
00613 sSummary = string2HTML( event->summary() );
00614 }
00615
00616 QString sLocation = i18n( "Location unspecified" );
00617 if ( ! event->location().isEmpty() ) {
00618 sLocation = string2HTML( event->location() );
00619 }
00620
00621 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00622 html = QString("<div dir=\"%1\">\n").arg(dir);
00623
00624 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
00625
00626
00627 html += invitationRow( i18n( "What:" ), sSummary );
00628 html += invitationRow( i18n( "Where:" ), sLocation );
00629
00630
00631 if ( ! event->doesFloat() ) {
00632 tmp = i18n("%1: Start Date, %2: Start Time", "%1 %2")
00633 .arg( event->dtStartDateStr(), event->dtStartTimeStr() );
00634 } else {
00635 tmp = i18n("%1: Start Date", "%1 (time unspecified)")
00636 .arg( event->dtStartDateStr() );
00637 }
00638 html += invitationRow( i18n( "Start Time:" ), tmp );
00639
00640
00641 if ( event->hasEndDate() ) {
00642 if ( ! event->doesFloat() ) {
00643 tmp = i18n("%1: End Date, %2: End Time", "%1 %2")
00644 .arg( event->dtEndDateStr(), event->dtEndTimeStr() );
00645 } else {
00646 tmp = i18n("%1: End Date", "%1 (time unspecified)")
00647 .arg( event->dtEndDateStr() );
00648 }
00649 } else {
00650 tmp = i18n( "Unspecified" );
00651 }
00652 html += invitationRow( i18n( "End Time:" ), tmp );
00653
00654
00655 if ( !event->doesFloat() && event->hasEndDate() ) {
00656 tmp = QString::null;
00657 QTime sDuration(0,0,0), t;
00658 int secs = event->dtStart().secsTo( event->dtEnd() );
00659 t = sDuration.addSecs( secs );
00660 if ( t.hour() > 0 ) {
00661 tmp += i18n( "1 hour ", "%n hours ", t.hour() );
00662 }
00663 if ( t.minute() > 0 ) {
00664 tmp += i18n( "1 minute ", "%n minutes ", t.minute() );
00665 }
00666
00667 html += invitationRow( i18n( "Duration:" ), tmp );
00668 }
00669
00670 html += "</table>\n";
00671 html += "</div>\n";
00672
00673 return html;
00674 }
00675
00676 static QString invitationDetailsTodo( Todo *todo )
00677 {
00678
00679 if ( !todo )
00680 return QString::null;
00681
00682 QString sSummary = i18n( "Summary unspecified" );
00683 QString sDescr = i18n( "Description unspecified" );
00684 if ( ! todo->summary().isEmpty() ) {
00685 sSummary = todo->summary();
00686 }
00687 if ( ! todo->description().isEmpty() ) {
00688 sDescr = todo->description();
00689 }
00690 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00691 html += invitationRow( i18n( "Summary:" ), sSummary );
00692 html += invitationRow( i18n( "Description:" ), sDescr );
00693 html += "</table>\n";
00694
00695 return html;
00696 }
00697
00698 static QString invitationDetailsJournal( Journal *journal )
00699 {
00700 if ( !journal )
00701 return QString::null;
00702
00703 QString sSummary = i18n( "Summary unspecified" );
00704 QString sDescr = i18n( "Description unspecified" );
00705 if ( ! journal->summary().isEmpty() ) {
00706 sSummary = journal->summary();
00707 }
00708 if ( ! journal->description().isEmpty() ) {
00709 sDescr = journal->description();
00710 }
00711 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00712 html += invitationRow( i18n( "Summary:" ), sSummary );
00713 html += invitationRow( i18n( "Date:" ), journal->dtStartDateStr( false ) );
00714 html += invitationRow( i18n( "Description:" ), sDescr );
00715 html += "</table>\n";
00716
00717 return html;
00718 }
00719
00720 static QString invitationDetailsFreeBusy( FreeBusy *fb )
00721 {
00722 if ( !fb )
00723 return QString::null;
00724 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00725
00726 html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
00727 html += invitationRow( i18n("Start date:"), fb->dtStartDateStr() );
00728 html += invitationRow( i18n("End date:"),
00729 KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
00730 html += "<tr><td colspan=2><hr></td></tr>\n";
00731 html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
00732
00733 QValueList<Period> periods = fb->busyPeriods();
00734
00735 QValueList<Period>::iterator it;
00736 for ( it = periods.begin(); it != periods.end(); ++it ) {
00737 Period per = *it;
00738 if ( per.hasDuration() ) {
00739 int dur = per.duration().asSeconds();
00740 QString cont;
00741 if ( dur >= 3600 ) {
00742 cont += i18n("1 hour ", "%n hours ", dur / 3600);
00743 dur %= 3600;
00744 }
00745 if ( dur >= 60 ) {
00746 cont += i18n("1 minute", "%n minutes ", dur / 60);
00747 dur %= 60;
00748 }
00749 if ( dur > 0 ) {
00750 cont += i18n("1 second", "%n seconds", dur);
00751 }
00752 html += invitationRow( QString::null, i18n("startDate for duration", "%1 for %2")
00753 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00754 .arg(cont) );
00755 } else {
00756 QString cont;
00757 if ( per.start().date() == per.end().date() ) {
00758 cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
00759 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
00760 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
00761 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
00762 } else {
00763 cont = i18n("fromDateTime - toDateTime", "%1 - %2")
00764 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00765 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
00766 }
00767
00768 html += invitationRow( QString::null, cont );
00769 }
00770 }
00771
00772 html += "</table>\n";
00773 return html;
00774 }
00775
00776 static QString invitationHeaderEvent( Event *event, ScheduleMessage *msg )
00777 {
00778 if ( !msg || !event )
00779 return QString::null;
00780 switch ( msg->method() ) {
00781 case Scheduler::Publish:
00782 return i18n("This event has been published");
00783 case Scheduler::Request:
00784 if ( event->revision() > 0 )
00785 return i18n( "This meeting has been updated" );
00786 return i18n( "You have been invited to this meeting" );
00787 case Scheduler::Refresh:
00788 return i18n( "This invitation was refreshed" );
00789 case Scheduler::Cancel:
00790 return i18n( "This meeting has been canceled" );
00791 case Scheduler::Add:
00792 return i18n( "Addition to the meeting invitation" );
00793 case Scheduler::Reply: {
00794 Attendee::List attendees = event->attendees();
00795 if( attendees.count() == 0 ) {
00796 kdDebug(5850) << "No attendees in the iCal reply!\n";
00797 return QString::null;
00798 }
00799 if( attendees.count() != 1 )
00800 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
00801 << "but is " << attendees.count() << endl;
00802 Attendee* attendee = *attendees.begin();
00803 QString attendeeName = attendee->name();
00804 if ( attendeeName.isEmpty() )
00805 attendeeName = attendee->email();
00806 if ( attendeeName.isEmpty() )
00807 attendeeName = i18n( "Sender" );
00808
00809 QString delegatorName, dummy;
00810 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
00811 if ( delegatorName.isEmpty() )
00812 delegatorName = attendee->delegator();
00813
00814 switch( attendee->status() ) {
00815 case Attendee::NeedsAction:
00816 return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
00817 case Attendee::Accepted:
00818 if ( delegatorName.isEmpty() )
00819 return i18n( "%1 accepts this meeting invitation" ).arg( attendeeName );
00820 return i18n( "%1 accepts this meeting invitation on behalf of %2" )
00821 .arg( attendeeName ).arg( delegatorName );
00822 case Attendee::Tentative:
00823 if ( delegatorName.isEmpty() )
00824 return i18n( "%1 tentatively accepts this meeting invitation" ).arg( attendeeName );
00825 return i18n( "%1 tentatively accepts this meeting invitation on behalf of %2" )
00826 .arg( attendeeName ).arg( delegatorName );
00827 case Attendee::Declined:
00828 if ( delegatorName.isEmpty() )
00829 return i18n( "%1 declines this meeting invitation" ).arg( attendeeName );
00830 return i18n( "%1 declines this meeting invitation on behalf of %2" )
00831 .arg( attendeeName ).arg( delegatorName );
00832 case Attendee::Delegated: {
00833 QString delegate, dummy;
00834 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
00835 if ( delegate.isEmpty() )
00836 delegate = attendee->delegate();
00837 if ( !delegate.isEmpty() )
00838 return i18n( "%1 has delegated this meeting invitation to %2" )
00839 .arg( attendeeName ) .arg( delegate );
00840 return i18n( "%1 has delegated this meeting invitation" ).arg( attendeeName );
00841 }
00842 case Attendee::Completed:
00843 return i18n( "This meeting invitation is now completed" );
00844 case Attendee::InProcess:
00845 return i18n( "%1 is still processing the invitation" ).arg( attendeeName );
00846 default:
00847 return i18n( "Unknown response to this meeting invitation" );
00848 }
00849 break; }
00850 case Scheduler::Counter:
00851 return i18n( "Sender makes this counter proposal" );
00852 case Scheduler::Declinecounter:
00853 return i18n( "Sender declines the counter proposal" );
00854 case Scheduler::NoMethod:
00855 return i18n("Error: iMIP message with unknown method: '%1'")
00856 .arg( msg->method() );
00857 }
00858 return QString::null;
00859 }
00860
00861 static QString invitationHeaderTodo( Todo *todo, ScheduleMessage *msg )
00862 {
00863 if ( !msg || !todo )
00864 return QString::null;
00865 switch ( msg->method() ) {
00866 case Scheduler::Publish:
00867 return i18n("This task has been published");
00868 case Scheduler::Request:
00869 if ( todo->revision() > 0 )
00870 return i18n( "This task has been updated" );
00871 return i18n( "You have been assigned this task" );
00872 case Scheduler::Refresh:
00873 return i18n( "This task was refreshed" );
00874 case Scheduler::Cancel:
00875 return i18n( "This task was canceled" );
00876 case Scheduler::Add:
00877 return i18n( "Addition to the task" );
00878 case Scheduler::Reply: {
00879 Attendee::List attendees = todo->attendees();
00880 if( attendees.count() == 0 ) {
00881 kdDebug(5850) << "No attendees in the iCal reply!\n";
00882 return QString::null;
00883 }
00884 if( attendees.count() != 1 )
00885 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
00886 << "but is " << attendees.count() << endl;
00887 Attendee* attendee = *attendees.begin();
00888
00889 switch( attendee->status() ) {
00890 case Attendee::NeedsAction:
00891 return i18n( "Sender indicates this task assignment still needs some action" );
00892 case Attendee::Accepted:
00893 return i18n( "Sender accepts this task" );
00894 case Attendee::Tentative:
00895 return i18n( "Sender tentatively accepts this task" );
00896 case Attendee::Declined:
00897 return i18n( "Sender declines this task" );
00898 case Attendee::Delegated: {
00899 QString delegate, dummy;
00900 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
00901 if ( delegate.isEmpty() )
00902 delegate = attendee->delegate();
00903 if ( !delegate.isEmpty() )
00904 return i18n( "Sender has delegated this request for the task to %1" ).arg( delegate );
00905 return i18n( "Sender has delegated this request for the task " );
00906 }
00907 case Attendee::Completed:
00908 return i18n( "The request for this task is now completed" );
00909 case Attendee::InProcess:
00910 return i18n( "Sender is still processing the invitation" );
00911 default:
00912 return i18n( "Unknown response to this task" );
00913 }
00914 break; }
00915 case Scheduler::Counter:
00916 return i18n( "Sender makes this counter proposal" );
00917 case Scheduler::Declinecounter:
00918 return i18n( "Sender declines the counter proposal" );
00919 case Scheduler::NoMethod:
00920 return i18n("Error: iMIP message with unknown method: '%1'")
00921 .arg( msg->method() );
00922 }
00923 return QString::null;
00924 }
00925
00926 static QString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
00927 {
00928
00929 if ( !msg || !journal )
00930 return QString::null;
00931 switch ( msg->method() ) {
00932 case Scheduler::Publish:
00933 return i18n("This journal has been published");
00934 case Scheduler::Request:
00935 return i18n( "You have been assigned this journal" );
00936 case Scheduler::Refresh:
00937 return i18n( "This journal was refreshed" );
00938 case Scheduler::Cancel:
00939 return i18n( "This journal was canceled" );
00940 case Scheduler::Add:
00941 return i18n( "Addition to the journal" );
00942 case Scheduler::Reply: {
00943 Attendee::List attendees = journal->attendees();
00944 if( attendees.count() == 0 ) {
00945 kdDebug(5850) << "No attendees in the iCal reply!\n";
00946 return QString::null;
00947 }
00948 if( attendees.count() != 1 )
00949 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
00950 << "but is " << attendees.count() << endl;
00951 Attendee* attendee = *attendees.begin();
00952
00953 switch( attendee->status() ) {
00954 case Attendee::NeedsAction:
00955 return i18n( "Sender indicates this journal assignment still needs some action" );
00956 case Attendee::Accepted:
00957 return i18n( "Sender accepts this journal" );
00958 case Attendee::Tentative:
00959 return i18n( "Sender tentatively accepts this journal" );
00960 case Attendee::Declined:
00961 return i18n( "Sender declines this journal" );
00962 case Attendee::Delegated:
00963 return i18n( "Sender has delegated this request for the journal" );
00964 case Attendee::Completed:
00965 return i18n( "The request for this journal is now completed" );
00966 case Attendee::InProcess:
00967 return i18n( "Sender is still processing the invitation" );
00968 default:
00969 return i18n( "Unknown response to this journal" );
00970 }
00971 break; }
00972 case Scheduler::Counter:
00973 return i18n( "Sender makes this counter proposal" );
00974 case Scheduler::Declinecounter:
00975 return i18n( "Sender declines the counter proposal" );
00976 case Scheduler::NoMethod:
00977 return i18n("Error: iMIP message with unknown method: '%1'")
00978 .arg( msg->method() );
00979 }
00980 return QString::null;
00981 }
00982
00983 static QString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
00984 {
00985 if ( !msg || !fb )
00986 return QString::null;
00987 switch ( msg->method() ) {
00988 case Scheduler::Publish:
00989 return i18n("This free/busy list has been published");
00990 case Scheduler::Request:
00991 return i18n( "The free/busy list has been requested" );
00992 case Scheduler::Refresh:
00993 return i18n( "This free/busy list was refreshed" );
00994 case Scheduler::Cancel:
00995 return i18n( "This free/busy list was canceled" );
00996 case Scheduler::Add:
00997 return i18n( "Addition to the free/busy list" );
00998 case Scheduler::NoMethod:
00999 default:
01000 return i18n("Error: Free/Busy iMIP message with unknown method: '%1'")
01001 .arg( msg->method() );
01002 }
01003 }
01004
01005 class IncidenceFormatter::ScheduleMessageVisitor : public IncidenceBase::Visitor
01006 {
01007 public:
01008 ScheduleMessageVisitor() : mMessage(0) { mResult = ""; }
01009 bool act( IncidenceBase *incidence, ScheduleMessage *msg ) { mMessage = msg; return incidence->accept( *this ); }
01010 QString result() const { return mResult; }
01011
01012 protected:
01013 QString mResult;
01014 ScheduleMessage *mMessage;
01015 };
01016
01017 class IncidenceFormatter::InvitationHeaderVisitor :
01018 public IncidenceFormatter::ScheduleMessageVisitor
01019 {
01020 protected:
01021 bool visit( Event *event )
01022 {
01023 mResult = invitationHeaderEvent( event, mMessage );
01024 return !mResult.isEmpty();
01025 }
01026 bool visit( Todo *todo )
01027 {
01028 mResult = invitationHeaderTodo( todo, mMessage );
01029 return !mResult.isEmpty();
01030 }
01031 bool visit( Journal *journal )
01032 {
01033 mResult = invitationHeaderJournal( journal, mMessage );
01034 return !mResult.isEmpty();
01035 }
01036 bool visit( FreeBusy *fb )
01037 {
01038 mResult = invitationHeaderFreeBusy( fb, mMessage );
01039 return !mResult.isEmpty();
01040 }
01041 };
01042
01043 class IncidenceFormatter::InvitationBodyVisitor :
01044 public IncidenceFormatter::ScheduleMessageVisitor
01045 {
01046 protected:
01047 bool visit( Event *event )
01048 {
01049 mResult = invitationDetailsEvent( event );
01050 return !mResult.isEmpty();
01051 }
01052 bool visit( Todo *todo )
01053 {
01054 mResult = invitationDetailsTodo( todo );
01055 return !mResult.isEmpty();
01056 }
01057 bool visit( Journal *journal )
01058 {
01059 mResult = invitationDetailsJournal( journal );
01060 return !mResult.isEmpty();
01061 }
01062 bool visit( FreeBusy *fb )
01063 {
01064 mResult = invitationDetailsFreeBusy( fb );
01065 return !mResult.isEmpty();
01066 }
01067 };
01068
01069
01070 QString InvitationFormatterHelper::makeLink( const QString &id, const QString &text )
01071 {
01072 QString res( "<a href=\"%1\"><b>%2</b></a>" );
01073 return res.arg( generateLinkURL( id ) ).arg( text );
01074 return res;
01075 }
01076
01077
01078 QString IncidenceFormatter::formatICalInvitation( QString invitation, Calendar *mCalendar,
01079 InvitationFormatterHelper *helper )
01080 {
01081 if ( invitation.isEmpty() ) return QString::null;
01082
01083 ICalFormat format;
01084
01085 ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
01086
01087 if( !msg ) {
01088 kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
01089 Q_ASSERT( format.exception() );
01090 kdDebug( 5850 ) << format.exception()->message() << endl;
01091 return QString::null;
01092 }
01093
01094 IncidenceBase *incBase = msg->event();
01095
01096
01097 QString html;
01098
01099 QString tableStyle = QString::fromLatin1(
01100 "style=\"border: solid 1px; margin: 0em;\"" );
01101 QString tableHead = QString::fromLatin1(
01102 "<div align=\"center\">"
01103 "<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
01104 "<tr><td>").arg(tableStyle);
01105
01106 html += tableHead;
01107 InvitationHeaderVisitor headerVisitor;
01108
01109 if ( !headerVisitor.act( incBase, msg ) )
01110 return QString::null;
01111 html += "<b>" + headerVisitor.result() + "</b>";
01112
01113 InvitationBodyVisitor bodyVisitor;
01114 if ( !bodyVisitor.act( incBase, msg ) )
01115 return QString::null;
01116 html += bodyVisitor.result();
01117
01118 html += "<br> <br> <br>";
01119 html += "<table border=\"0\" cellspacing=\"0\"><tr><td> </td></tr><tr>";
01120
01121 #if 0
01122 html += helper->makeLinkURL( "accept", i18n("[Enter this into my calendar]") );
01123 html += "</td><td> </td><td>";
01124 #endif
01125
01126
01127
01128 switch ( msg->method() ) {
01129 case Scheduler::Publish:
01130 case Scheduler::Request:
01131 case Scheduler::Refresh:
01132 case Scheduler::Add:
01133 {
01134 Incidence *inc = dynamic_cast<Incidence*>( incBase );
01135 if ( inc && inc->revision() > 0 ) {
01136 if ( incBase->type() == "Todo" ) {
01137 html += "<td colspan=\"9\">";
01138 html += helper->makeLink( "reply", i18n( "[Enter this into my task list]" ) );
01139 } else {
01140 html += "<td colspan=\"13\">";
01141 html += helper->makeLink( "reply", i18n( "[Enter this into my calendar]" ) );
01142 }
01143 html += "</td></tr><tr>";
01144 }
01145 html += "<td>";
01146
01147
01148 html += helper->makeLink( "accept", i18n( "[Accept]" ) );
01149 html += "</td><td> </td><td>";
01150 html += helper->makeLink( "accept_conditionally",
01151 i18n( "Accept conditionally", "[Accept cond.]" ) );
01152 html += "</td><td> </td><td>";
01153
01154 html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
01155 html += "</td><td> </td><td>";
01156
01157 html += helper->makeLink( "decline", i18n( "[Decline]" ) );
01158 html += "</td><td> </td><td>";
01159
01160
01161 html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
01162 html += "</td><td> </td><td>";
01163
01164
01165 html += helper->makeLink( "forward", i18n( "[Forward]" ) );
01166
01167 if ( incBase->type() == "Event" ) {
01168 html += "</b></a></td><td> </td><td>";
01169 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
01170 }
01171 break;
01172 }
01173
01174 case Scheduler::Cancel:
01175
01176 html += helper->makeLink( "cancel", i18n( "[Remove this from my calendar]" ) );
01177 break;
01178
01179 case Scheduler::Reply:
01180
01181 if ( incBase->type() == "Todo" ) {
01182 html += helper->makeLink( "reply", i18n( "[Enter this into my task list]" ) );
01183 } else {
01184 html += helper->makeLink( "reply", i18n( "[Enter this into my calendar]" ) );
01185 }
01186 break;
01187
01188 case Scheduler::Counter:
01189 case Scheduler::Declinecounter:
01190 case Scheduler::NoMethod:
01191 break;
01192 }
01193
01194 html += "</td></tr></table>";
01195
01196 Incidence* incidence = dynamic_cast<Incidence*>( incBase );
01197 if ( incidence ) {
01198 QString sDescr = incidence->description();
01199 if( !sDescr.isEmpty() ) {
01200 html += "<br> <br> <br><u>" + i18n("Description:")
01201 + "</u><br><table border=\"0\"><tr><td> </td><td>";
01202 html += string2HTML(sDescr) + "</td></tr></table>";
01203 }
01204 QStringList comments = incidence->comments();
01205 if ( !comments.isEmpty() ) {
01206 html += "<br><u>" + i18n("Comments:")
01207 + "</u><br><table border=\"0\"><tr><td> </td><td><ul>";
01208 for ( uint i = 0; i < comments.count(); ++i )
01209 html += "<li>" + string2HTML( comments[i] ) + "</li>";
01210 html += "</ul></td></tr></table>";
01211 }
01212 }
01213
01214 html += "</td></tr></table><br></div>";
01215
01216 return html;
01217 }
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
01230 const QString& fallback = QString::null)
01231 {
01232 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
01233 fallback );
01234 }
01235
01236 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
01237 const QString& fallback = QString::null )
01238 {
01239 return tnefMsg->findNamedProp( name, fallback );
01240 }
01241
01242 struct save_tz { char* old_tz; char* tz_env_str; };
01243
01244
01245 static struct save_tz set_tz( const char* _tc )
01246 {
01247 const char *tc = _tc?_tc:"UTC";
01248
01249 struct save_tz rv;
01250
01251 rv.old_tz = 0;
01252 rv.tz_env_str = 0;
01253
01254
01255
01256 char* tz_env = 0;
01257 if( getenv( "TZ" ) ) {
01258 tz_env = strdup( getenv( "TZ" ) );
01259 rv.old_tz = tz_env;
01260 }
01261 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
01262 strcpy( tmp_env, "TZ=" );
01263 strcpy( tmp_env+3, tc );
01264 putenv( tmp_env );
01265
01266 rv.tz_env_str = tmp_env;
01267
01268
01269
01270 tzset();
01271
01272
01273 return rv;
01274 }
01275
01276
01277 static void unset_tz( struct save_tz old_tz )
01278 {
01279 if( old_tz.old_tz ) {
01280 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
01281 strcpy( tmp_env, "TZ=" );
01282 strcpy( tmp_env+3, old_tz.old_tz );
01283 putenv( tmp_env );
01284
01285 free( old_tz.old_tz );
01286 } else {
01287
01288 putenv( strdup("TZ") );
01289 }
01290 tzset();
01291
01292
01293 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
01294 }
01295
01296 static QDateTime utc2Local( const QDateTime& utcdt )
01297 {
01298 struct tm tmL;
01299
01300 save_tz tmp_tz = set_tz("UTC");
01301 time_t utc = utcdt.toTime_t();
01302 unset_tz( tmp_tz );
01303
01304 localtime_r( &utc, &tmL );
01305 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
01306 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
01307 }
01308
01309
01310 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
01311 bool bDateOnly = false )
01312 {
01313 QDate tmpDate;
01314 QTime tmpTime;
01315 int year, month, day, hour, minute, second;
01316
01317 if( bDateOnly ) {
01318 year = dtStr.left( 4 ).toInt();
01319 month = dtStr.mid( 4, 2 ).toInt();
01320 day = dtStr.mid( 6, 2 ).toInt();
01321 hour = 0;
01322 minute = 0;
01323 second = 0;
01324 } else {
01325 year = dtStr.left( 4 ).toInt();
01326 month = dtStr.mid( 4, 2 ).toInt();
01327 day = dtStr.mid( 6, 2 ).toInt();
01328 hour = dtStr.mid( 9, 2 ).toInt();
01329 minute = dtStr.mid( 11, 2 ).toInt();
01330 second = dtStr.mid( 13, 2 ).toInt();
01331 }
01332 tmpDate.setYMD( year, month, day );
01333 tmpTime.setHMS( hour, minute, second );
01334
01335 if( tmpDate.isValid() && tmpTime.isValid() ) {
01336 QDateTime dT = QDateTime( tmpDate, tmpTime );
01337
01338 if( !bDateOnly ) {
01339
01340 if (dtStr.at(dtStr.length()-1) == 'Z') {
01341
01342
01343 dT = utc2Local( dT );
01344 }
01345 }
01346 return dT;
01347 } else
01348 return QDateTime();
01349 }
01350
01351
01352
01353 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
01354 {
01355 bool bOk = false;
01356
01357 KTNEFParser parser;
01358 QBuffer buf( tnef );
01359 CalendarLocal cal ( QString::fromLatin1( "UTC" ) );
01360 KABC::Addressee addressee;
01361 KABC::VCardConverter cardConv;
01362 ICalFormat calFormat;
01363 Event* event = new Event();
01364
01365 if( parser.openDevice( &buf ) ) {
01366 KTNEFMessage* tnefMsg = parser.message();
01367
01368
01369
01370
01371 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
01372 .upper();
01373 if( !msgClass.isEmpty() ) {
01374
01375
01376 bool bCompatClassAppointment = false;
01377 bool bCompatMethodRequest = false;
01378 bool bCompatMethodCancled = false;
01379 bool bCompatMethodAccepted = false;
01380 bool bCompatMethodAcceptedCond = false;
01381 bool bCompatMethodDeclined = false;
01382 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
01383 bCompatClassAppointment = true;
01384 if( msgClass.endsWith( ".MTGREQ" ) )
01385 bCompatMethodRequest = true;
01386 if( msgClass.endsWith( ".MTGCNCL" ) )
01387 bCompatMethodCancled = true;
01388 if( msgClass.endsWith( ".MTGRESPP" ) )
01389 bCompatMethodAccepted = true;
01390 if( msgClass.endsWith( ".MTGRESPA" ) )
01391 bCompatMethodAcceptedCond = true;
01392 if( msgClass.endsWith( ".MTGRESPN" ) )
01393 bCompatMethodDeclined = true;
01394 }
01395 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
01396
01397 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
01398
01399 bool bIsReply = false;
01400 QString prodID = "-//Microsoft Corporation//Outlook ";
01401 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
01402 prodID += "MIMEDIR/EN\n";
01403 prodID += "VERSION:2.0\n";
01404 calFormat.setApplication( "Outlook", prodID );
01405
01406 Scheduler::Method method;
01407 if( bCompatMethodRequest )
01408 method = Scheduler::Request;
01409 else if( bCompatMethodCancled )
01410 method = Scheduler::Cancel;
01411 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
01412 bCompatMethodDeclined ) {
01413 method = Scheduler::Reply;
01414 bIsReply = true;
01415 } else {
01416
01417
01418
01419
01420
01421
01422
01423
01424 if( tnefMsg->findProp(0x0c17) == "1" )
01425 bIsReply = true;
01426 method = Scheduler::Request;
01427 }
01428
01430 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
01431
01432 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
01433
01434 if( !sSenderSearchKeyEmail.isEmpty() ) {
01435 int colon = sSenderSearchKeyEmail.find( ':' );
01436
01437 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
01438 sSenderSearchKeyEmail.remove( 0, colon+1 );
01439 }
01440
01441 QString s( tnefMsg->findProp( 0x0e04 ) );
01442 QStringList attendees = QStringList::split( ';', s );
01443 if( attendees.count() ) {
01444 for( QStringList::Iterator it = attendees.begin();
01445 it != attendees.end(); ++it ) {
01446
01447
01448 if( (*it).find('@') == -1 ) {
01449 s = (*it).stripWhiteSpace();
01450
01451 Attendee *attendee = new Attendee( s, s, true );
01452 if( bIsReply ) {
01453 if( bCompatMethodAccepted )
01454 attendee->setStatus( Attendee::Accepted );
01455 if( bCompatMethodDeclined )
01456 attendee->setStatus( Attendee::Declined );
01457 if( bCompatMethodAcceptedCond )
01458 attendee->setStatus(Attendee::Tentative);
01459 } else {
01460 attendee->setStatus( Attendee::NeedsAction );
01461 attendee->setRole( Attendee::ReqParticipant );
01462 }
01463 event->addAttendee(attendee);
01464 }
01465 }
01466 } else {
01467
01468
01469 s = sSenderSearchKeyEmail;
01470 if( !s.isEmpty() ) {
01471 Attendee *attendee = new Attendee( QString::null, QString::null,
01472 true );
01473 if( bIsReply ) {
01474 if( bCompatMethodAccepted )
01475 attendee->setStatus( Attendee::Accepted );
01476 if( bCompatMethodAcceptedCond )
01477 attendee->setStatus( Attendee::Declined );
01478 if( bCompatMethodDeclined )
01479 attendee->setStatus( Attendee::Tentative );
01480 } else {
01481 attendee->setStatus(Attendee::NeedsAction);
01482 attendee->setRole(Attendee::ReqParticipant);
01483 }
01484 event->addAttendee(attendee);
01485 }
01486 }
01487 s = tnefMsg->findProp( 0x0c1f );
01488 if( s.isEmpty() && !bIsReply )
01489 s = sSenderSearchKeyEmail;
01490
01491 if( !s.isEmpty() )
01492 event->setOrganizer( s );
01493
01494 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
01495 .replace( QChar( ':' ), QString::null );
01496 event->setDtStart( QDateTime::fromString( s ) );
01497
01498 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
01499 .replace( QChar( ':' ), QString::null );
01500 event->setDtEnd( QDateTime::fromString( s ) );
01501
01502 s = tnefMsg->findProp( 0x8208 );
01503 event->setLocation( s );
01504
01505
01506
01507
01508
01509
01510 s = tnefMsg->findProp( 0x0023 );
01511 event->setUid( s );
01512
01513
01514
01515
01516 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
01517 .replace( QChar( ':' ), QString::null );
01518
01519
01520
01521 s = tnefMsg->findNamedProp( "Keywords" );
01522 event->setCategories( s );
01523
01524 s = tnefMsg->findProp( 0x1000 );
01525 event->setDescription( s );
01526
01527 s = tnefMsg->findProp( 0x0070 );
01528 event->setSummary( s );
01529
01530 s = tnefMsg->findProp( 0x0026 );
01531 event->setPriority( s.toInt() );
01532
01533
01534 if(!tnefMsg->findProp(0x8503).isEmpty()) {
01535 Alarm *alarm = new Alarm(event);
01536 QDateTime highNoonTime =
01537 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
01538 .replace( QChar( '-' ), "" )
01539 .replace( QChar( ':' ), "" ) );
01540 QDateTime wakeMeUpTime =
01541 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
01542 .replace( QChar( '-' ), "" )
01543 .replace( QChar( ':' ), "" ) );
01544 alarm->setTime(wakeMeUpTime);
01545
01546 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
01547 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
01548 else
01549
01550 alarm->setStartOffset( Duration( 15*60 ) );
01551 alarm->setDisplayAlarm( i18n( "Reminder" ) );
01552
01553
01554
01555 event->addAlarm( alarm );
01556 }
01557 cal.addEvent( event );
01558 bOk = true;
01559
01560 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
01561 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
01562 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
01563 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
01564 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
01565 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
01566 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
01567 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
01568 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
01569 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
01570 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
01571 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
01572 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
01573
01574 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
01575 .replace( QChar( '-' ), QString::null )
01576 .replace( QChar( ':' ), QString::null );
01577 if( !s.isEmpty() )
01578 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
01579
01580 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
01581
01582
01583 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
01584 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
01585 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
01586 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
01587 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
01588
01589 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
01590 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
01591 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
01592
01593
01594
01595
01596
01597 KABC::Address adr;
01598 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
01599 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
01600 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
01601 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
01602 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
01603 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
01604 adr.setType(KABC::Address::Home);
01605 addressee.insertAddress(adr);
01606
01607 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
01608 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
01609 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
01610 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
01611 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
01612 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
01613 adr.setType( KABC::Address::Work );
01614 addressee.insertAddress( adr );
01615
01616 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
01617 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
01618 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
01619 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
01620 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
01621 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
01622 adr.setType( KABC::Address::Dom );
01623 addressee.insertAddress(adr);
01624
01625
01626
01627
01628
01629 QString nr;
01630 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
01631 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
01632 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
01633 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
01634 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
01635 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
01636 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
01637 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
01638 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
01639 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
01640
01641 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
01642 .replace( QChar( '-' ), QString::null )
01643 .replace( QChar( ':' ), QString::null );
01644 if( !s.isEmpty() )
01645 addressee.setBirthday( QDateTime::fromString( s ) );
01646
01647 bOk = ( !addressee.isEmpty() );
01648 } else if( "IPM.NOTE" == msgClass ) {
01649
01650 }
01651 }
01652 }
01653
01654
01655 QString iCal = calFormat.toString( &cal );
01656 if( !iCal.isEmpty() )
01657
01658 return iCal;
01659
01660
01661 KABC::VCardConverter converter;
01662 return converter.createVCard( addressee );
01663 }
01664
01665
01666 QString IncidenceFormatter::formatTNEFInvitation( const QByteArray& tnef,
01667 Calendar *mCalendar, InvitationFormatterHelper *helper )
01668 {
01669 QString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
01670 QString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
01671 if( !iCal.isEmpty() )
01672 return iCal;
01673 return vPart;
01674 }
01675
01676
01677
01678
01679
01680
01681
01682
01683 class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
01684 {
01685 public:
01686 ToolTipVisitor() : mRichText( true ), mResult( "" ) {}
01687
01688 bool act( IncidenceBase *incidence, bool richText=true)
01689 {
01690 mRichText = richText;
01691 mResult = "";
01692 return incidence ? incidence->accept( *this ) : false;
01693 }
01694 QString result() const { return mResult; }
01695
01696 protected:
01697 bool visit( Event *event );
01698 bool visit( Todo *todo );
01699 bool visit( Journal *journal );
01700 bool visit( FreeBusy *fb );
01701
01702 QString dateRangeText( Event*event );
01703 QString dateRangeText( Todo *todo );
01704 QString dateRangeText( Journal *journal );
01705 QString dateRangeText( FreeBusy *fb );
01706
01707 QString generateToolTip( Incidence* incidence, QString dtRangeText );
01708
01709 protected:
01710 bool mRichText;
01711 QString mResult;
01712 };
01713
01714 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event*event )
01715 {
01716 QString ret;
01717 QString tmp;
01718 if ( event->isMultiDay() ) {
01719
01720 tmp = "<br>" + i18n("Event start", "<i>From:</i> %1");
01721 if (event->doesFloat())
01722 ret += tmp.arg( event->dtStartDateStr().replace(" ", " ") );
01723 else
01724 ret += tmp.arg( event->dtStartStr().replace(" ", " ") );
01725
01726 tmp = "<br>" + i18n("Event end","<i>To:</i> %1");
01727 if (event->doesFloat())
01728 ret += tmp.arg( event->dtEndDateStr().replace(" ", " ") );
01729 else
01730 ret += tmp.arg( event->dtEndStr().replace(" ", " ") );
01731
01732 } else {
01733
01734 ret += "<br>"+i18n("<i>Date:</i> %1").
01735 arg( event->dtStartDateStr().replace(" ", " ") );
01736 if ( !event->doesFloat() ) {
01737 if ( event->dtStartTimeStr() == event->dtEndTimeStr() ) {
01738 tmp = "<br>" + i18n("time for event, to prevent ugly line breaks",
01739 "<i>Time:</i> %1").
01740 arg( event->dtStartTimeStr().replace(" ", " ") );
01741 } else {
01742 tmp = "<br>" + i18n("time range for event, to prevent ugly line breaks",
01743 "<i>Time:</i> %1 - %2").
01744 arg( event->dtStartTimeStr().replace(" ", " ") ).
01745 arg( event->dtEndTimeStr().replace(" ", " ") );
01746 }
01747 ret += tmp;
01748 }
01749
01750 }
01751 return ret;
01752 }
01753
01754 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo*todo )
01755 {
01756 QString ret;
01757 bool floats( todo->doesFloat() );
01758 if (todo->hasStartDate())
01759
01760
01761
01762 ret += "<br>" + i18n("<i>Start:</i> %1").arg(
01763 (floats)
01764 ?(todo->dtStartDateStr().replace(" ", " "))
01765 :(todo->dtStartStr().replace(" ", " ")) ) ;
01766 if (todo->hasDueDate())
01767 ret += "<br>" + i18n("<i>Due:</i> %1").arg(
01768 (floats)
01769 ?(todo->dtDueDateStr().replace(" ", " "))
01770 :(todo->dtDueStr().replace(" ", " ")) );
01771 if (todo->isCompleted())
01772 ret += "<br>" + i18n("<i>Completed:</i> %1").arg( todo->completedStr().replace(" ", " ") );
01773 else
01774 ret += "<br>" + i18n("%1 % completed").arg(todo->percentComplete());
01775
01776 return ret;
01777 }
01778
01779 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
01780 {
01781 QString ret;
01782 if (journal->dtStart().isValid() ) {
01783 ret += "<br>" + i18n("<i>Date:</i> %1").arg( journal->dtStartDateStr( false ) );
01784 }
01785 return ret;
01786 }
01787
01788 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
01789 {
01790 QString tmp( "<br>" + i18n("<i>Period start:</i> %1") );
01791 QString ret = tmp.arg( KGlobal::locale()->formatDateTime( fb->dtStart() ) );
01792 tmp = "<br>" + i18n("<i>Period start:</i> %1");
01793 ret += tmp.arg( KGlobal::locale()->formatDateTime( fb->dtEnd() ) );
01794 return ret;
01795 }
01796
01797
01798
01799 bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
01800 {
01801 mResult = generateToolTip( event, dateRangeText( event ) );
01802 return !mResult.isEmpty();
01803 }
01804
01805 bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
01806 {
01807 mResult = generateToolTip( todo, dateRangeText( todo ) );
01808 return !mResult.isEmpty();
01809 }
01810
01811 bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
01812 {
01813 mResult = generateToolTip( journal, dateRangeText( journal ) );
01814 return !mResult.isEmpty();
01815 }
01816
01817 bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
01818 {
01819 mResult = "<qt><b>" + i18n("Free/Busy information for %1")
01820 .arg(fb->organizer().fullName()) + "</b>";
01821 mResult += dateRangeText( fb );
01822 mResult += "</qt>";
01823 return !mResult.isEmpty();
01824 }
01825
01826 QString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, QString dtRangeText )
01827 {
01828 if ( !incidence )
01829 return QString::null;
01830
01831 QString tmp = "<qt><b>"+ incidence->summary().replace("\n", "<br>")+"</b>";
01832
01833 tmp += dtRangeText;
01834
01835 if (!incidence->location().isEmpty()) {
01836
01837 tmp += "<br>"+i18n("<i>Location:</i> %1").
01838 arg( incidence->location().replace("\n", "<br>") );
01839 }
01840 if (!incidence->description().isEmpty()) {
01841 QString desc(incidence->description());
01842 if (desc.length()>120) {
01843 desc = desc.left(120) + "...";
01844 }
01845 tmp += "<br>----------<br>" + i18n("<i>Description:</i><br>") + desc.replace("\n", "<br>");
01846 }
01847 tmp += "</qt>";
01848 return tmp;
01849 }
01850
01851 QString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
01852 {
01853 ToolTipVisitor v;
01854 if ( v.act( incidence, richText ) ) {
01855 return v.result();
01856 } else
01857 return QString::null;
01858 }
01859
01860
01861
01862
01863
01864
01865
01866
01867 class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
01868 {
01869 public:
01870 MailBodyVisitor() : mResult( "" ) {}
01871
01872 bool act( IncidenceBase *incidence )
01873 {
01874 mResult = "";
01875 return incidence ? incidence->accept( *this ) : false;
01876 }
01877 QString result() const { return mResult; }
01878
01879 protected:
01880 bool visit( Event *event );
01881 bool visit( Todo *todo );
01882 bool visit( Journal *journal );
01883 bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
01884 protected:
01885 QString mResult;
01886 };
01887
01888
01889 static QString mailBodyIncidence( Incidence *incidence )
01890 {
01891 QString body;
01892 if ( !incidence->summary().isEmpty() ) {
01893 body += i18n("Summary: %1\n").arg( incidence->summary() );
01894 }
01895 if ( !incidence->organizer().isEmpty() ) {
01896 body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
01897 }
01898 if ( !incidence->location().isEmpty() ) {
01899 body += i18n("Location: %1\n").arg( incidence->location() );
01900 }
01901 return body;
01902 }
01903
01904 bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
01905 {
01906 QString recurrence[]= {i18n("no recurrence", "None"),
01907 i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
01908 i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
01909 i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
01910
01911 mResult = mailBodyIncidence( event );
01912 mResult += i18n("Start Date: %1\n").arg( event->dtStartDateStr() );
01913 if ( !event->doesFloat() ) {
01914 mResult += i18n("Start Time: %1\n").arg( event->dtStartTimeStr() );
01915 }
01916 if ( event->dtStart() != event->dtEnd() ) {
01917 mResult += i18n("End Date: %1\n").arg( event->dtEndDateStr() );
01918 }
01919 if ( !event->doesFloat() ) {
01920 mResult += i18n("End Time: %1\n").arg( event->dtEndTimeStr() );
01921 }
01922 if ( event->doesRecur() ) {
01923 Recurrence *recur = event->recurrence();
01924
01925 mResult += i18n("Recurs: %1\n")
01926 .arg( recurrence[ recur->recurrenceType() ] );
01927 mResult += i18n("Frequency: %1\n")
01928 .arg( event->recurrence()->frequency() );
01929
01930 if ( recur->duration() > 0 ) {
01931 mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
01932 mResult += '\n';
01933 } else {
01934 if ( recur->duration() != -1 ) {
01935
01936 QString endstr;
01937 if ( event->doesFloat() ) {
01938 endstr = KGlobal::locale()->formatDate( recur->endDate() );
01939 } else {
01940 endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
01941 }
01942 mResult += i18n("Repeat until: %1\n").arg( endstr );
01943 } else {
01944 mResult += i18n("Repeats forever\n");
01945 }
01946 }
01947 }
01948 QString details = event->description();
01949 if ( !details.isEmpty() ) {
01950 mResult += i18n("Details:\n%1\n").arg( details );
01951 }
01952 return !mResult.isEmpty();
01953 }
01954
01955 bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
01956 {
01957 mResult = mailBodyIncidence( todo );
01958
01959 if ( todo->hasStartDate() ) {
01960 mResult += i18n("Start Date: %1\n").arg( todo->dtStartDateStr() );
01961 if ( !todo->doesFloat() ) {
01962 mResult += i18n("Start Time: %1\n").arg( todo->dtStartTimeStr() );
01963 }
01964 }
01965 if ( todo->hasDueDate() ) {
01966 mResult += i18n("Due Date: %1\n").arg( todo->dtDueDateStr() );
01967 if ( !todo->doesFloat() ) {
01968 mResult += i18n("Due Time: %1\n").arg( todo->dtDueTimeStr() );
01969 }
01970 }
01971 QString details = todo->description();
01972 if ( !details.isEmpty() ) {
01973 mResult += i18n("Details:\n%1\n").arg( details );
01974 }
01975 return !mResult.isEmpty();
01976 }
01977
01978 bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
01979 {
01980 mResult = mailBodyIncidence( journal );
01981 mResult += i18n("Date: %1\n").arg( journal->dtStartDateStr() );
01982 if ( !journal->doesFloat() ) {
01983 mResult += i18n("Time: %1\n").arg( journal->dtStartTimeStr() );
01984 }
01985 if ( !journal->description().isEmpty() )
01986 mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
01987 return !mResult.isEmpty();
01988 }
01989
01990
01991
01992 QString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
01993 {
01994 if ( !incidence )
01995 return QString::null;
01996
01997 MailBodyVisitor v;
01998 if ( v.act( incidence ) ) {
01999 return v.result();
02000 }
02001 return QString::null;
02002 }