00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "htmlexport.h"
00023 #include "htmlexportsettings.h"
00024 #include "stringify.h"
00025
00026 #include <kcalcore/memorycalendar.h>
00027 using namespace KCalCore;
00028
00029 #include <KDebug>
00030 #include <KCalendarSystem>
00031 #include <KGlobal>
00032 #include <KLocale>
00033
00034 #include <QtCore/QFile>
00035 #include <QtCore/QMap>
00036 #include <QtCore/QTextStream>
00037 #include <QtGui/QApplication>
00038
00039 using namespace KCalUtils;
00040
00041 static QString cleanChars( const QString &txt );
00042
00043
00044 class KCalUtils::HtmlExport::Private
00045 {
00046 public:
00047 Private( MemoryCalendar *calendar, HTMLExportSettings *settings )
00048 : mCalendar( calendar ), mSettings( settings )
00049 {}
00050
00051 MemoryCalendar *mCalendar;
00052 HTMLExportSettings *mSettings;
00053 QMap<QDate,QString> mHolidayMap;
00054 };
00055
00056
00057 HtmlExport::HtmlExport( MemoryCalendar *calendar, HTMLExportSettings *settings )
00058 : d( new Private( calendar, settings ) )
00059 {
00060 }
00061
00062 HtmlExport::~HtmlExport()
00063 {
00064 delete d;
00065 }
00066
00067 bool HtmlExport::save( const QString &fileName )
00068 {
00069 QString fn( fileName );
00070 if ( fn.isEmpty() && d->mSettings ) {
00071 fn = d->mSettings->outputFile();
00072 }
00073 if ( !d->mSettings || fn.isEmpty() ) {
00074 return false;
00075 }
00076 QFile f( fileName );
00077 if ( !f.open( QIODevice::WriteOnly ) ) {
00078 return false;
00079 }
00080 QTextStream ts( &f );
00081 bool success = save( &ts );
00082 f.close();
00083 return success;
00084 }
00085
00086 bool HtmlExport::save( QTextStream *ts )
00087 {
00088 if ( !d->mSettings ) {
00089 return false;
00090 }
00091 ts->setCodec( "UTF-8" );
00092
00093 *ts << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ";
00094 *ts << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl;
00095
00096 *ts << "<html><head>" << endl;
00097 *ts << " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=";
00098 *ts << "UTF-8\" />" << endl;
00099 if ( !d->mSettings->pageTitle().isEmpty() ) {
00100 *ts << " <title>" << d->mSettings->pageTitle() << "</title>" << endl;
00101 }
00102 *ts << " <style type=\"text/css\">" << endl;
00103 *ts << styleSheet();
00104 *ts << " </style>" << endl;
00105 *ts << "</head><body>" << endl;
00106
00107
00108
00109
00110 if ( d->mSettings->eventView() || d->mSettings->monthView() || d->mSettings->weekView() ) {
00111 if ( !d->mSettings->eventTitle().isEmpty() ) {
00112 *ts << "<h1>" << d->mSettings->eventTitle() << "</h1>" << endl;
00113 }
00114
00115
00116 if ( d->mSettings->weekView() ) {
00117 createWeekView( ts );
00118 }
00119
00120 if ( d->mSettings->monthView() ) {
00121 createMonthView( ts );
00122 }
00123
00124 if ( d->mSettings->eventView() ) {
00125 createEventList( ts );
00126 }
00127 }
00128
00129
00130 if ( d->mSettings->todoView() ) {
00131 if ( !d->mSettings->todoListTitle().isEmpty() ) {
00132 *ts << "<h1>" << d->mSettings->todoListTitle() << "</h1>" << endl;
00133 }
00134 createTodoList( ts );
00135 }
00136
00137
00138 if ( d->mSettings->journalView() ) {
00139 if ( !d->mSettings->journalTitle().isEmpty() ) {
00140 *ts << "<h1>" << d->mSettings->journalTitle() << "</h1>" << endl;
00141 }
00142 createJournalView( ts );
00143 }
00144
00145
00146 if ( d->mSettings->freeBusyView() ) {
00147 if ( !d->mSettings->freeBusyTitle().isEmpty() ) {
00148 *ts << "<h1>" << d->mSettings->freeBusyTitle() << "</h1>" << endl;
00149 }
00150 createFreeBusyView( ts );
00151 }
00152
00153 createFooter( ts );
00154
00155
00156 *ts << "</body></html>" << endl;
00157
00158 return true;
00159 }
00160
00161 void HtmlExport::createMonthView( QTextStream *ts )
00162 {
00163 QDate start = fromDate();
00164 start.setYMD( start.year(), start.month(), 1 );
00165
00166 QDate end( start.year(), start.month(), start.daysInMonth() );
00167
00168 int startmonth = start.month();
00169 int startyear = start.year();
00170
00171 while ( start < toDate() ) {
00172
00173 QDate hDate( start.year(), start.month(), 1 );
00174 QString hMon = hDate.toString( "MMMM" );
00175 QString hYear = hDate.toString( "yyyy" );
00176 *ts << "<h2>"
00177 << i18nc( "@title month and year", "%1 %2", hMon, hYear )
00178 << "</h2>" << endl;
00179 if ( KGlobal::locale()->weekStartDay() == 1 ) {
00180 start = start.addDays( 1 - start.dayOfWeek() );
00181 } else {
00182 if ( start.dayOfWeek() != 7 ) {
00183 start = start.addDays( -start.dayOfWeek() );
00184 }
00185 }
00186 *ts << "<table border=\"1\">" << endl;
00187
00188
00189 *ts << " <tr>";
00190 for ( int i=0; i < 7; ++i ) {
00191 *ts << "<th>" << KGlobal::locale()->calendar()->weekDayName( start.addDays(i) ) << "</th>";
00192 }
00193 *ts << "</tr>" << endl;
00194
00195
00196 while ( start <= end ) {
00197 *ts << " <tr>" << endl;
00198 for ( int i=0; i < 7; ++i ) {
00199 *ts << " <td valign=\"top\"><table border=\"0\">";
00200
00201 *ts << "<tr><td ";
00202 if ( d->mHolidayMap.contains( start ) || start.dayOfWeek() == 7 ) {
00203 *ts << "class=\"dateholiday\"";
00204 } else {
00205 *ts << "class=\"date\"";
00206 }
00207 *ts << ">" << QString::number( start.day() );
00208
00209 if ( d->mHolidayMap.contains( start ) ) {
00210 *ts << " <em>" << d->mHolidayMap[start] << "</em>";
00211 }
00212
00213 *ts << "</td></tr><tr><td valign=\"top\">";
00214
00215
00216 if ( start >= fromDate() && start <= toDate() ) {
00217 Event::List events = d->mCalendar->events( start, d->mCalendar->timeSpec(),
00218 EventSortStartDate,
00219 SortDirectionAscending );
00220 if ( events.count() ) {
00221 *ts << "<table>";
00222 Event::List::ConstIterator it;
00223 for ( it = events.constBegin(); it != events.constEnd(); ++it ) {
00224 if ( checkSecrecy( *it ) ) {
00225 createEvent( ts, *it, start, false );
00226 }
00227 }
00228 *ts << "</table>";
00229 } else {
00230 *ts << " ";
00231 }
00232 }
00233
00234 *ts << "</td></tr></table></td>" << endl;
00235 start = start.addDays( 1 );
00236 }
00237 *ts << " </tr>" << endl;
00238 }
00239 *ts << "</table>" << endl;
00240 startmonth += 1;
00241 if ( startmonth > 12 ) {
00242 startyear += 1;
00243 startmonth = 1;
00244 }
00245 start.setYMD( startyear, startmonth, 1 );
00246 end.setYMD( start.year(), start.month(), start.daysInMonth() );
00247 }
00248 }
00249
00250 void HtmlExport::createEventList( QTextStream *ts )
00251 {
00252 int columns = 3;
00253 *ts << "<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">" << endl;
00254 *ts << " <tr>" << endl;
00255 *ts << " <th class=\"sum\">" << i18nc( "@title:column event start time",
00256 "Start Time" ) << "</th>" << endl;
00257 *ts << " <th>" << i18nc( "@title:column event end time",
00258 "End Time" ) << "</th>" << endl;
00259 *ts << " <th>" << i18nc( "@title:column event description",
00260 "Event" ) << "</th>" << endl;
00261 if ( d->mSettings->eventLocation() ) {
00262 *ts << " <th>" << i18nc( "@title:column event locatin",
00263 "Location" ) << "</th>" << endl;
00264 ++columns;
00265 }
00266 if ( d->mSettings->eventCategories() ) {
00267 *ts << " <th>" << i18nc( "@title:column event categories",
00268 "Categories" ) << "</th>" << endl;
00269 ++columns;
00270 }
00271 if ( d->mSettings->eventAttendees() ) {
00272 *ts << " <th>" << i18nc( "@title:column event attendees",
00273 "Attendees" ) << "</th>" << endl;
00274 ++columns;
00275 }
00276
00277 *ts << " </tr>" << endl;
00278
00279 for ( QDate dt = fromDate(); dt <= toDate(); dt = dt.addDays(1) ) {
00280 kDebug() << "Getting events for" << dt.toString();
00281 Event::List events = d->mCalendar->events( dt, d->mCalendar->timeSpec(),
00282 EventSortStartDate,
00283 SortDirectionAscending );
00284 if ( events.count() ) {
00285 *ts << " <tr><td colspan=\"" << QString::number( columns )
00286 << "\" class=\"datehead\"><i>"
00287 << KGlobal::locale()->formatDate( dt )
00288 << "</i></td></tr>" << endl;
00289
00290 Event::List::ConstIterator it;
00291 for ( it = events.constBegin(); it != events.constEnd(); ++it ) {
00292 if ( checkSecrecy( *it ) ) {
00293 createEvent( ts, *it, dt );
00294 }
00295 }
00296 }
00297 }
00298
00299 *ts << "</table>" << endl;
00300 }
00301
00302 void HtmlExport::createEvent ( QTextStream *ts,
00303 const Event::Ptr &event,
00304 const QDate &date,
00305 bool withDescription )
00306 {
00307 kDebug() << event->summary();
00308 *ts << " <tr>" << endl;
00309
00310 if ( !event->allDay() ) {
00311 if ( event->isMultiDay( d->mCalendar->timeSpec() ) && ( event->dtStart().date() != date ) ) {
00312 *ts << " <td> </td>" << endl;
00313 } else {
00314 *ts << " <td valign=\"top\">"
00315 << Stringify::formatTime( event->dtStart(), true, d->mCalendar->timeSpec() )
00316 << "</td>" << endl;
00317 }
00318 if ( event->isMultiDay( d->mCalendar->timeSpec() ) && ( event->dtEnd().date() != date ) ) {
00319 *ts << " <td> </td>" << endl;
00320 } else {
00321 *ts << " <td valign=\"top\">"
00322 << Stringify::formatTime( event->dtEnd(), true, d->mCalendar->timeSpec() )
00323 << "</td>" << endl;
00324 }
00325 } else {
00326 *ts << " <td> </td><td> </td>" << endl;
00327 }
00328
00329 *ts << " <td class=\"sum\">" << endl;
00330 *ts << " <b>" << cleanChars( event->summary() ) << "</b>" << endl;
00331 if ( withDescription && !event->description().isEmpty() ) {
00332 *ts << " <p>" << breakString( cleanChars( event->description() ) ) << "</p>" << endl;
00333 }
00334 *ts << " </td>" << endl;
00335
00336 if ( d->mSettings->eventLocation() ) {
00337 *ts << " <td>" << endl;
00338 formatLocation( ts, event );
00339 *ts << " </td>" << endl;
00340 }
00341
00342 if ( d->mSettings->eventCategories() ) {
00343 *ts << " <td>" << endl;
00344 formatCategories( ts, event );
00345 *ts << " </td>" << endl;
00346 }
00347
00348 if ( d->mSettings->eventAttendees() ) {
00349 *ts << " <td>" << endl;
00350 formatAttendees( ts, event );
00351 *ts << " </td>" << endl;
00352 }
00353
00354 *ts << " </tr>" << endl;
00355 }
00356
00357 void HtmlExport::createTodoList ( QTextStream *ts )
00358 {
00359 Todo::List rawTodoList = d->mCalendar->todos();
00360
00361 int index = 0;
00362 while ( index < rawTodoList.count() ) {
00363 Todo::Ptr ev = rawTodoList[ index ];
00364 Todo::Ptr subev = ev;
00365 const QString uid = ev->relatedTo();
00366 if ( !uid.isEmpty() ) {
00367 Incidence::Ptr inc = d->mCalendar->incidence( uid );
00368 if ( inc && inc->type() == Incidence::TypeTodo ) {
00369 Todo::Ptr todo = inc.staticCast<Todo>();
00370 if ( !rawTodoList.contains( todo ) ) {
00371 rawTodoList.append( todo );
00372 }
00373 }
00374 }
00375 index = rawTodoList.indexOf( subev );
00376 ++index;
00377 }
00378
00379
00380
00381 Todo::List todoList;
00382 Todo::List::ConstIterator it;
00383 for ( int i = 1; i <= 9; ++i ) {
00384 for ( it = rawTodoList.constBegin(); it != rawTodoList.constEnd(); ++it ) {
00385 if ( (*it)->priority() == i && checkSecrecy( *it ) ) {
00386 todoList.append( *it );
00387 }
00388 }
00389 }
00390 for ( it = rawTodoList.constBegin(); it != rawTodoList.constEnd(); ++it ) {
00391 if ( (*it)->priority() == 0 && checkSecrecy( *it ) ) {
00392 todoList.append( *it );
00393 }
00394 }
00395
00396 int columns = 3;
00397 *ts << "<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">" << endl;
00398 *ts << " <tr>" << endl;
00399 *ts << " <th class=\"sum\">" << i18nc( "@title:column", "To-do" ) << "</th>" << endl;
00400 *ts << " <th>" << i18nc( "@title:column to-do priority", "Priority" ) << "</th>" << endl;
00401 *ts << " <th>" << i18nc( "@title:column to-do percent completed",
00402 "Completed" ) << "</th>" << endl;
00403 if ( d->mSettings->taskDueDate() ) {
00404 *ts << " <th>" << i18nc( "@title:column to-do due date", "Due Date" ) << "</th>" << endl;
00405 ++columns;
00406 }
00407 if ( d->mSettings->taskLocation() ) {
00408 *ts << " <th>" << i18nc( "@title:column to-do location", "Location" ) << "</th>" << endl;
00409 ++columns;
00410 }
00411 if ( d->mSettings->taskCategories() ) {
00412 *ts << " <th>" << i18nc( "@title:column to-do categories", "Categories" ) << "</th>" << endl;
00413 ++columns;
00414 }
00415 if ( d->mSettings->taskAttendees() ) {
00416 *ts << " <th>" << i18nc( "@title:column to-do attendees", "Attendees" ) << "</th>" << endl;
00417 ++columns;
00418 }
00419 *ts << " </tr>" << endl;
00420
00421
00422 for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) {
00423 if ( (*it)->relatedTo().isEmpty() ) {
00424 createTodo( ts, *it );
00425 }
00426 }
00427
00428
00429 for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) {
00430 Incidence::List relations = d->mCalendar->relations( ( *it )->uid() );
00431
00432 if ( relations.count() ) {
00433
00434 *ts << " <tr>" << endl;
00435 *ts << " <td class=\"subhead\" colspan=";
00436 *ts << "\"" << QString::number(columns) << "\"";
00437 *ts << "><a name=\"sub" << (*it)->uid() << "\"></a>"
00438 << i18nc( "@title:column sub-to-dos of the parent to-do",
00439 "Sub-To-dos of: " ) << "<a href=\"#"
00440 << (*it)->uid() << "\"><b>" << cleanChars( (*it)->summary() )
00441 << "</b></a></td>" << endl;
00442 *ts << " </tr>" << endl;
00443
00444 Todo::List sortedList;
00445
00446
00447 for ( int i = 1; i <= 9; ++i ) {
00448 Incidence::List::ConstIterator it2;
00449 for ( it2 = relations.constBegin(); it2 != relations.constEnd(); ++it2 ) {
00450 Todo::Ptr ev3 = (*it2).staticCast<Todo>();
00451 if ( ev3 && ev3->priority() == i ) {
00452 sortedList.append( ev3 );
00453 }
00454 }
00455 }
00456 Incidence::List::ConstIterator it2;
00457 for ( it2 = relations.constBegin(); it2 != relations.constEnd(); ++it2 ) {
00458 Todo::Ptr ev3 = (*it2).staticCast<Todo>();
00459 if ( ev3 && ev3->priority() == 0 ) {
00460 sortedList.append( ev3 );
00461 }
00462 }
00463
00464 Todo::List::ConstIterator it3;
00465 for ( it3 = sortedList.constBegin(); it3 != sortedList.constEnd(); ++it3 ) {
00466 createTodo( ts, *it3 );
00467 }
00468 }
00469 }
00470
00471 *ts << "</table>" << endl;
00472 }
00473
00474 void HtmlExport::createTodo( QTextStream *ts, const Todo::Ptr &todo )
00475 {
00476 kDebug();
00477
00478 const bool completed = todo->isCompleted();
00479
00480 Incidence::List relations = d->mCalendar->relations( todo->uid() );
00481
00482 *ts << "<tr>" << endl;
00483
00484 *ts << " <td class=\"sum";
00485 if (completed) *ts << "done";
00486 *ts << "\">" << endl;
00487 *ts << " <a name=\"" << todo->uid() << "\"></a>" << endl;
00488 *ts << " <b>" << cleanChars( todo->summary() ) << "</b>" << endl;
00489 if ( !todo->description().isEmpty() ) {
00490 *ts << " <p>" << breakString( cleanChars( todo->description() ) ) << "</p>" << endl;
00491 }
00492 if ( relations.count() ) {
00493 *ts << " <div align=\"right\"><a href=\"#sub" << todo->uid()
00494 << "\">" << i18nc( "@title:column sub-to-dos of the parent to-do",
00495 "Sub-To-dos" ) << "</a></div>" << endl;
00496 }
00497 *ts << " </td>" << endl;
00498
00499 *ts << " <td";
00500 if ( completed ) {
00501 *ts << " class=\"done\"";
00502 }
00503 *ts << ">" << endl;
00504 *ts << " " << todo->priority() << endl;
00505 *ts << " </td>" << endl;
00506
00507 *ts << " <td";
00508 if ( completed ) {
00509 *ts << " class=\"done\"";
00510 }
00511 *ts << ">" << endl;
00512 *ts << " " << i18nc( "@info/plain to-do percent complete",
00513 "%1 %", todo->percentComplete() ) << endl;
00514 *ts << " </td>" << endl;
00515
00516 if ( d->mSettings->taskDueDate() ) {
00517 *ts << " <td";
00518 if ( completed ) {
00519 *ts << " class=\"done\"";
00520 }
00521 *ts << ">" << endl;
00522 if ( todo->hasDueDate() ) {
00523 *ts << " " << Stringify::formatDate( todo->dtDue( true ) ) << endl;
00524 } else {
00525 *ts << " " << endl;
00526 }
00527 *ts << " </td>" << endl;
00528 }
00529
00530 if ( d->mSettings->taskLocation() ) {
00531 *ts << " <td";
00532 if ( completed ) {
00533 *ts << " class=\"done\"";
00534 }
00535 *ts << ">" << endl;
00536 formatLocation( ts, todo );
00537 *ts << " </td>" << endl;
00538 }
00539
00540 if ( d->mSettings->taskCategories() ) {
00541 *ts << " <td";
00542 if ( completed ) {
00543 *ts << " class=\"done\"";
00544 }
00545 *ts << ">" << endl;
00546 formatCategories( ts, todo );
00547 *ts << " </td>" << endl;
00548 }
00549
00550 if ( d->mSettings->taskAttendees() ) {
00551 *ts << " <td";
00552 if ( completed ) {
00553 *ts << " class=\"done\"";
00554 }
00555 *ts << ">" << endl;
00556 formatAttendees( ts, todo );
00557 *ts << " </td>" << endl;
00558 }
00559
00560 *ts << "</tr>" << endl;
00561 }
00562
00563 void HtmlExport::createWeekView( QTextStream *ts )
00564 {
00565 Q_UNUSED( ts );
00566
00567 }
00568
00569 void HtmlExport::createJournalView( QTextStream *ts )
00570 {
00571 Q_UNUSED( ts );
00572
00573
00574 }
00575
00576 void HtmlExport::createFreeBusyView( QTextStream *ts )
00577 {
00578 Q_UNUSED( ts );
00579
00580 }
00581
00582 bool HtmlExport::checkSecrecy( const Incidence::Ptr &incidence )
00583 {
00584 int secrecy = incidence->secrecy();
00585 if ( secrecy == Incidence::SecrecyPublic ) {
00586 return true;
00587 }
00588 if ( secrecy == Incidence::SecrecyPrivate && !d->mSettings->excludePrivate() ) {
00589 return true;
00590 }
00591 if ( secrecy == Incidence::SecrecyConfidential &&
00592 !d->mSettings->excludeConfidential() ) {
00593 return true;
00594 }
00595 return false;
00596 }
00597
00598 void HtmlExport::formatLocation( QTextStream *ts,
00599 const Incidence::Ptr &incidence )
00600 {
00601 if ( !incidence->location().isEmpty() ) {
00602 *ts << " " << cleanChars( incidence->location() ) << endl;
00603 } else {
00604 *ts << " " << endl;
00605 }
00606 }
00607
00608 void HtmlExport::formatCategories( QTextStream *ts,
00609 const Incidence::Ptr &incidence )
00610 {
00611 if ( !incidence->categoriesStr().isEmpty() ) {
00612 *ts << " " << cleanChars( incidence->categoriesStr() ) << endl;
00613 } else {
00614 *ts << " " << endl;
00615 }
00616 }
00617
00618 void HtmlExport::formatAttendees( QTextStream *ts,
00619 const Incidence::Ptr &incidence )
00620 {
00621 Attendee::List attendees = incidence->attendees();
00622 if ( attendees.count() ) {
00623 *ts << "<em>";
00624 *ts << incidence->organizer()->fullName();
00625 *ts << "</em><br />";
00626 Attendee::List::ConstIterator it;
00627 for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) {
00628 Attendee::Ptr a( *it );
00629 if ( !a->email().isEmpty() ) {
00630 *ts << "<a href=\"mailto:" << a->email();
00631 *ts << "\">" << cleanChars( a->name() ) << "</a>";
00632 } else {
00633 *ts << " " << cleanChars( a->name() );
00634 }
00635 *ts << "<br />" << endl;
00636 }
00637 } else {
00638 *ts << " " << endl;
00639 }
00640 }
00641
00642 QString HtmlExport::breakString( const QString &text )
00643 {
00644 int number = text.count( "\n" );
00645 if ( number <= 0 ) {
00646 return text;
00647 } else {
00648 QString out;
00649 QString tmpText = text;
00650 int pos = 0;
00651 QString tmp;
00652 for ( int i = 0; i <= number; ++i ) {
00653 pos = tmpText.indexOf( "\n" );
00654 tmp = tmpText.left( pos );
00655 tmpText = tmpText.right( tmpText.length() - pos - 1 );
00656 out += tmp + "<br />";
00657 }
00658 return out;
00659 }
00660 }
00661
00662 void HtmlExport::createFooter( QTextStream *ts )
00663 {
00664
00665 QString trailer = i18nc( "@info/plain", "This page was created " );
00666
00667
00668
00669
00670
00671 if ( !d->mSettings->eMail().isEmpty() ) {
00672 if ( !d->mSettings->name().isEmpty() ) {
00673 trailer += i18nc( "@info/plain page creator email link with name",
00674 "by <link url='mailto:%1'>%2</link> ",
00675 d->mSettings->eMail(), d->mSettings->name() );
00676 } else {
00677 trailer += i18nc( "@info/plain page creator email link",
00678 "by <link url='mailto:%1'>%2</link> ",
00679 d->mSettings->eMail(), d->mSettings->eMail() );
00680 }
00681 } else {
00682 if ( !d->mSettings->name().isEmpty() ) {
00683 trailer += i18nc( "@info/plain page creator name only",
00684 "by %1 ", d->mSettings->name() );
00685 }
00686 }
00687 if ( !d->mSettings->creditName().isEmpty() ) {
00688 if ( !d->mSettings->creditURL().isEmpty() ) {
00689 trailer += i18nc( "@info/plain page credit with name and link",
00690 "with <link url='%1'>%2</link>",
00691 d->mSettings->creditURL(), d->mSettings->creditName() );
00692 } else {
00693 trailer += i18nc( "@info/plain page credit name only",
00694 "with %1", d->mSettings->creditName() );
00695 }
00696 }
00697 *ts << "<p>" << trailer << "</p>" << endl;
00698 }
00699
00700 QString cleanChars( const QString &text )
00701 {
00702 QString txt = text;
00703 txt = txt.replace( '&', "&" );
00704 txt = txt.replace( '<', "<" );
00705 txt = txt.replace( '>', ">" );
00706 txt = txt.replace( '\"', """ );
00707 txt = txt.replace( QString::fromUtf8( "ä" ), "ä" );
00708 txt = txt.replace( QString::fromUtf8( "Ä" ), "Ä" );
00709 txt = txt.replace( QString::fromUtf8( "ö" ), "ö" );
00710 txt = txt.replace( QString::fromUtf8( "Ö" ), "Ö" );
00711 txt = txt.replace( QString::fromUtf8( "ü" ), "ü" );
00712 txt = txt.replace( QString::fromUtf8( "Ü" ), "Ü" );
00713 txt = txt.replace( QString::fromUtf8( "ß" ), "ß" );
00714 txt = txt.replace( QString::fromUtf8( "€" ), "€" );
00715 txt = txt.replace( QString::fromUtf8( "é" ), "é" );
00716
00717 return txt;
00718 }
00719
00720 QString HtmlExport::styleSheet() const
00721 {
00722 if ( !d->mSettings->styleSheet().isEmpty() ) {
00723 return d->mSettings->styleSheet();
00724 }
00725
00726 QString css;
00727
00728 if ( QApplication::isRightToLeft() ) {
00729 css += " body { background-color:white; color:black; direction: rtl }\n";
00730 css += " td { text-align:center; background-color:#eee }\n";
00731 css += " th { text-align:center; background-color:#228; color:white }\n";
00732 css += " td.sumdone { background-color:#ccc }\n";
00733 css += " td.done { background-color:#ccc }\n";
00734 css += " td.subhead { text-align:center; background-color:#ccf }\n";
00735 css += " td.datehead { text-align:center; background-color:#ccf }\n";
00736 css += " td.space { background-color:white }\n";
00737 css += " td.dateholiday { color:red }\n";
00738 } else {
00739 css += " body { background-color:white; color:black }\n";
00740 css += " td { text-align:center; background-color:#eee }\n";
00741 css += " th { text-align:center; background-color:#228; color:white }\n";
00742 css += " td.sum { text-align:left }\n";
00743 css += " td.sumdone { text-align:left; background-color:#ccc }\n";
00744 css += " td.done { background-color:#ccc }\n";
00745 css += " td.subhead { text-align:center; background-color:#ccf }\n";
00746 css += " td.datehead { text-align:center; background-color:#ccf }\n";
00747 css += " td.space { background-color:white }\n";
00748 css += " td.date { text-align:left }\n";
00749 css += " td.dateholiday { text-align:left; color:red }\n";
00750 }
00751
00752 return css;
00753 }
00754
00755 void HtmlExport::addHoliday( const QDate &date, const QString &name )
00756 {
00757 if ( d->mHolidayMap[date].isEmpty() ) {
00758 d->mHolidayMap[date] = name;
00759 } else {
00760 d->mHolidayMap[date] = i18nc( "@info/plain holiday by date and name",
00761 "%1, %2", d->mHolidayMap[date], name );
00762 }
00763 }
00764
00765 QDate HtmlExport::fromDate() const
00766 {
00767 return d->mSettings->dateStart().date();
00768 }
00769
00770 QDate HtmlExport::toDate() const
00771 {
00772 return d->mSettings->dateEnd().date();
00773 }