00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
#include <qapplication.h>
00026
#include <qfile.h>
00027
#include <qtextstream.h>
00028
#include <qtextcodec.h>
00029
#include <qregexp.h>
00030
00031
#include <kglobal.h>
00032
#include <klocale.h>
00033
#include <kdebug.h>
00034
#include <kcalendarsystem.h>
00035
00036
#include <libkcal/calendar.h>
00037
#include <libkcal/event.h>
00038
#include <libkcal/todo.h>
00039
00040
#ifndef KORG_NOKABC
00041
#include <kabc/stdaddressbook.h>
00042
#endif
00043
#include "htmlexport.h"
00044
00045
using namespace KCal;
00046
00047 HtmlExport::HtmlExport(
Calendar *calendar ) :
00048 mCalendar( calendar ),
00049 mMonthViewEnabled( true ), mEventsEnabled( false ), mTodosEnabled( true ),
00050 mCategoriesTodoEnabled( false ), mAttendeesTodoEnabled( false ),
00051 mCategoriesEventEnabled( false ), mAttendeesEventEnabled( false ),
00052 mDueDateEnabled( false ),
00053 mExcludePrivateTodoEnabled( false ),
00054 mExcludeConfidentialTodoEnabled( false ),
00055 mExcludePrivateEventEnabled( false ),
00056 mExcludeConfidentialEventEnabled( false )
00057 {
00058 mTitle = i18n(
"KOrganizer Calendar");
00059 mTitleTodo = i18n(
"KOrganizer To-Do List");
00060 mCreditName =
"KOrganizer";
00061 mCreditURL =
"http://korganizer.kde.org";
00062 }
00063
00064 bool HtmlExport::save(
const QString &fileName)
00065 {
00066 QFile f(fileName);
00067
if (!f.open(IO_WriteOnly)) {
00068
return false;
00069 }
00070 QTextStream ts(&f);
00071
bool success =
save(&ts);
00072 f.close();
00073
return success;
00074 }
00075
00076 bool HtmlExport::save(QTextStream *ts)
00077 {
00078 ts->setEncoding(QTextStream::UnicodeUTF8);
00079
00080
00081 *ts <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ";
00082 *ts <<
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
00083
00084 *ts <<
"<html><head>" << endl;
00085 *ts <<
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=";
00086 *ts <<
"UTF-8\" />\n";
00087
if (!mTitle.isEmpty())
00088 *ts <<
" <title>" << mTitle <<
"</title>\n";
00089 *ts <<
" <style type=\"text/css\">\n";
00090 *ts << styleSheet();
00091 *ts <<
" </style>\n";
00092 *ts <<
"</head><body>\n";
00093
00094
00095
00096
00097
if (eventsEnabled() || monthViewEnabled()) {
00098
if (!mTitle.isEmpty())
00099 *ts <<
"<h1>" << mTitle <<
"</h1>\n";
00100 }
00101
00102
00103
if (monthViewEnabled()) {
00104 createHtmlMonthView(ts);
00105 }
00106
00107
00108
if (eventsEnabled()) {
00109
00110 createHtmlEventList(ts);
00111 }
00112
00113
00114
if (todosEnabled()) {
00115
if (!mTitleTodo.isEmpty())
00116 *ts <<
"<h1>" << mTitleTodo <<
"</h1>\n";
00117
00118
00119 createHtmlTodoList(ts);
00120 }
00121
00122
00123 QString trailer = i18n(
"This page was created ");
00124
00125
if (!mEmail.isEmpty()) {
00126
if (!mName.isEmpty())
00127 trailer += i18n(
"by <a href=\"mailto:%1\">%2</a> ").arg( mEmail ).arg( mName );
00128
else
00129 trailer += i18n(
"by <a href=\"mailto:%1\">%2</a> ").arg( mEmail ).arg( mEmail );
00130 }
else {
00131
if (!mName.isEmpty())
00132 trailer += i18n(
"by %1 ").arg( mName );
00133 }
00134
if (!mCreditName.isEmpty()) {
00135
if (!mCreditURL.isEmpty())
00136 trailer += i18n(
"with <a href=\"%1\">%2</a>").arg( mCreditURL ).arg( mCreditName );
00137
else
00138 trailer += i18n(
"with %1").arg( mCreditName );
00139 }
00140 *ts <<
"<p>" << trailer <<
"</p>\n";
00141
00142
00143 *ts <<
"</body></html>\n";
00144
00145
return true;
00146 }
00147
00148
void HtmlExport::createHtmlMonthView(QTextStream *ts)
00149 {
00150 QDate start = fromDate();
00151 start.setYMD(start.year(),start.month(),1);
00152
00153 QDate end(start.year(),start.month(),start.daysInMonth());
00154
00155
int startmonth = start.month();
00156
int startyear = start.year();
00157
00158
while ( start < toDate() ) {
00159
00160 *ts <<
"<h2>" << (i18n(
"month_year",
"%1 %2").arg(KGlobal::locale()->calendar()->monthName(start))
00161 .arg(start.year())) <<
"</h2>\n";
00162
if ( KGlobal::locale()->weekStartDay() == 1 ) {
00163 start = start.addDays(1 - start.dayOfWeek());
00164 }
else {
00165
if (start.dayOfWeek() != 7) {
00166 start = start.addDays(-start.dayOfWeek());
00167 }
00168 }
00169 *ts <<
"<table border=\"1\">\n";
00170
00171
00172 *ts <<
" <tr>";
00173
for(
int i=0; i<7; ++i) {
00174 *ts <<
"<th>" << KGlobal::locale()->calendar()->weekDayName( start.addDays(i) ) <<
"</th>";
00175 }
00176 *ts <<
"</tr>\n";
00177
00178
00179
while (start <= end) {
00180 *ts <<
" <tr>\n";
00181
for(
int i=0;i<7;++i) {
00182 *ts <<
" <td valign=\"top\"><table border=\"0\">";
00183
00184 *ts <<
"<tr><td ";
00185
if (mHolidayMap.contains(start) || start.dayOfWeek() == 7) {
00186 *ts <<
"class=\"dateholiday\"";
00187 }
else {
00188 *ts <<
"class=\"date\"";
00189 }
00190 *ts <<
">" << QString::number(start.day());
00191
00192
if (mHolidayMap.contains(start)) {
00193 *ts <<
" <em>" << mHolidayMap[start] <<
"</em>";
00194 }
00195
00196 *ts <<
"</td></tr><tr><td valign=\"top\">";
00197
00198 Event::List events = mCalendar->
events(start,
true);
00199
if (events.count()) {
00200 *ts <<
"<table>";
00201 Event::List::ConstIterator it;
00202
for( it = events.begin(); it != events.end(); ++it ) {
00203
if ( checkSecrecy( *it ) ) {
00204 createHtmlEvent( ts, *it, start,
false );
00205 }
00206 }
00207 *ts <<
"</table>";
00208 }
else {
00209 *ts <<
" ";
00210 }
00211
00212 *ts <<
"</td></tr></table></td>\n";
00213 start = start.addDays(1);
00214 }
00215 *ts <<
" </tr>\n";
00216 }
00217 *ts <<
"</table>\n";
00218 startmonth += 1;
00219
if ( startmonth > 12 ) {
00220 startyear += 1;
00221 startmonth = 1;
00222 }
00223 start.setYMD( startyear, startmonth, 1 );
00224 end.setYMD(start.year(),start.month(),start.daysInMonth());
00225 }
00226 }
00227
00228
void HtmlExport::createHtmlEventList (QTextStream *ts)
00229 {
00230 *ts <<
"<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
00231 *ts <<
" <tr>\n";
00232 *ts <<
" <th class=\"sum\">" << i18n(
"Start Time") <<
"</th>\n";
00233 *ts <<
" <th>" << i18n(
"End Time") <<
"</th>\n";
00234 *ts <<
" <th>" << i18n(
"Event") <<
"</th>\n";
00235
if (categoriesEventEnabled()) {
00236 *ts <<
" <th>" << i18n(
"Categories") <<
"</th>\n";
00237 }
00238
if (attendeesEventEnabled()) {
00239 *ts <<
" <th>" << i18n(
"Attendees") <<
"</th>\n";
00240 }
00241
00242 *ts <<
" </tr>\n";
00243
00244
int columns = 3;
00245
if (categoriesEventEnabled()) ++columns;
00246
if (attendeesEventEnabled()) ++columns;
00247
00248
for (QDate dt = fromDate(); dt <= toDate(); dt = dt.addDays(1)) {
00249 kdDebug(5850) <<
"Getting events for " << dt.toString() << endl;
00250 Event::List events = mCalendar->
events(dt,
true);
00251
if (events.count()) {
00252 *ts <<
" <tr><td colspan=\"" << QString::number(columns)
00253 <<
"\" class=\"datehead\"><i>"
00254 << KGlobal::locale()->formatDate(dt)
00255 <<
"</i></td></tr>\n";
00256
00257 Event::List::ConstIterator it;
00258
for( it = events.begin(); it != events.end(); ++it ) {
00259
if ( checkSecrecy( *it ) ) {
00260 createHtmlEvent( ts, *it, dt );
00261 }
00262 }
00263 }
00264 }
00265
00266 *ts <<
"</table>\n";
00267 }
00268
00269
void HtmlExport::createHtmlEvent (QTextStream *ts,
Event *event,
00270 QDate date,
bool withDescription)
00271 {
00272 kdDebug(5850) <<
"HtmlExport::createHtmlEvent(): " << event->
summary() << endl;
00273 *ts <<
" <tr>\n";
00274
00275
if (!event->
doesFloat()) {
00276
if (event->
isMultiDay() && (event->
dtStart().date() != date)) {
00277 *ts <<
" <td> </td>\n";
00278 }
else {
00279 *ts <<
" <td valign=\"top\">" << event->
dtStartTimeStr() <<
"</td>\n";
00280 }
00281
if (event->
isMultiDay() && (event->
dtEnd().date() != date)) {
00282 *ts <<
" <td> </td>\n";
00283 }
else {
00284 *ts <<
" <td valign=\"top\">" << event->
dtEndTimeStr() <<
"</td>\n";
00285 }
00286 }
else {
00287 *ts <<
" <td> </td><td> </td>\n";
00288 }
00289
00290 *ts <<
" <td class=\"sum\">\n";
00291 *ts <<
" <b>" << cleanChars(event->
summary()) <<
"</b>\n";
00292
if (withDescription && !event->
description().isEmpty()) {
00293 *ts <<
" <p>" << breakString(cleanChars(event->
description())) <<
"</p>\n";
00294 }
00295 *ts <<
" </td>\n";
00296
00297
if (categoriesEventEnabled()) {
00298 *ts <<
" <td>\n";
00299 formatHtmlCategories(ts,event);
00300 *ts <<
" </td>\n";
00301 }
00302
00303
if (attendeesEventEnabled()) {
00304 *ts <<
" <td>\n";
00305 formatHtmlAttendees(ts,event);
00306 *ts <<
" </td>\n";
00307 }
00308
00309 *ts <<
" </tr>\n";
00310 }
00311
00312
void HtmlExport::createHtmlTodoList ( QTextStream *ts )
00313 {
00314 Todo::List rawTodoList = mCalendar->
todos();
00315
00316 Todo::List::Iterator it = rawTodoList.begin();
00317
while ( it != rawTodoList.end() ) {
00318
Todo *ev = *it;
00319
Todo *subev = ev;
00320
if ( ev->
relatedTo() ) {
00321
if ( ev->
relatedTo()->
type()==
"Todo" ) {
00322
if ( rawTodoList.find( static_cast<Todo *>( ev->
relatedTo() ) ) ==
00323 rawTodoList.end() ) {
00324 rawTodoList.append( static_cast<Todo *>( ev->
relatedTo() ) );
00325 }
00326 }
00327 }
00328 it = rawTodoList.find( subev );
00329 ++it;
00330 }
00331
00332
00333
00334 Todo::List todoList;
00335
for (
int i = 1; i <= 5; ++i ) {
00336
for( it = rawTodoList.begin(); it != rawTodoList.end(); ++it ) {
00337
if ( (*it)->priority() == i && checkSecrecy( *it ) ) {
00338 todoList.append( *it );
00339 }
00340 }
00341 }
00342
00343 *ts <<
"<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
00344 *ts <<
" <tr>\n";
00345 *ts <<
" <th class=\"sum\">" << i18n(
"Task") <<
"</th>\n";
00346 *ts <<
" <th>" << i18n(
"Priority") <<
"</th>\n";
00347 *ts <<
" <th>" << i18n(
"Completed") <<
"</th>\n";
00348
if (dueDateEnabled()) {
00349 *ts <<
" <th>" << i18n(
"Due Date") <<
"</th>\n";
00350 }
00351
if (categoriesTodoEnabled()) {
00352 *ts <<
" <th>" << i18n(
"Categories") <<
"</th>\n";
00353 }
00354
if (attendeesTodoEnabled()) {
00355 *ts <<
" <th>" << i18n(
"Attendees") <<
"</th>\n";
00356 }
00357 *ts <<
" </tr>\n";
00358
00359
00360
for( it = todoList.begin(); it != todoList.end(); ++it ) {
00361
if ( !(*it)->relatedTo() ) createHtmlTodo( ts, *it );
00362 }
00363
00364
00365
for( it = todoList.begin(); it != todoList.end(); ++it ) {
00366 Incidence::List relations = (*it)->
relations();
00367
if (relations.count()) {
00368
00369 *ts <<
" <tr>\n";
00370 *ts <<
" <td class=\"subhead\" colspan=";
00371
int columns = 3;
00372
if (dueDateEnabled()) ++columns;
00373
if (categoriesTodoEnabled()) ++columns;
00374
if (attendeesTodoEnabled()) ++columns;
00375 *ts <<
"\"" << QString::number(columns) <<
"\"";
00376 *ts <<
"><a name=\"sub" << (*it)->uid() <<
"\"></a>"
00377 << i18n(
"Sub-Tasks of: ") <<
"<a href=\"#"
00378 << (*it)->uid() <<
"\"><b>" << cleanChars( (*it)->summary())
00379 <<
"</b></a></td>\n";
00380 *ts <<
" </tr>\n";
00381
00382 Todo::List sortedList;
00383
00384
00385
for (
int i = 1; i <= 5; ++i ) {
00386 Incidence::List::ConstIterator it2;
00387
for( it2 = relations.begin(); it2 != relations.end(); ++it2 ) {
00388
Todo *ev3 = dynamic_cast<Todo *>( *it2 );
00389
if ( ev3 && ev3->
priority() == i ) sortedList.append( ev3 );
00390 }
00391 }
00392
00393 Todo::List::ConstIterator it3;
00394
for( it3 = sortedList.begin(); it3 != sortedList.end(); ++it3 ) {
00395 createHtmlTodo( ts, *it3 );
00396 }
00397 }
00398 }
00399
00400 *ts <<
"</table>\n";
00401 }
00402
00403
void HtmlExport::createHtmlTodo (QTextStream *ts,
Todo *todo)
00404 {
00405 kdDebug(5850) <<
"HtmlExport::createHtmlTodo()" << endl;
00406
00407
bool completed = todo->
isCompleted();
00408 Incidence::List relations = todo->
relations();
00409
00410 *ts <<
"<tr>\n";
00411
00412 *ts <<
" <td class=\"sum\"";
00413
if (completed) *ts <<
"done";
00414 *ts <<
">\n";
00415 *ts <<
" <a name=\"" << todo->
uid() <<
"\"></a>\n";
00416 *ts <<
" <b>" << cleanChars(todo->
summary()) <<
"</b>\n";
00417
if (!todo->
description().isEmpty()) {
00418 *ts <<
" <p>" << breakString(cleanChars(todo->
description())) <<
"</p>\n";
00419 }
00420
if (relations.count()) {
00421 *ts <<
" <div align=\"right\"><a href=\"#sub" << todo->
uid()
00422 <<
"\">" << i18n(
"Sub-Tasks") <<
"</a></div>\n";
00423 }
00424
00425 *ts <<
" </td";
00426
if (completed) *ts <<
" class=\"done\"";
00427 *ts <<
">\n";
00428
00429 *ts <<
" <td";
00430
if (completed) *ts <<
" class=\"done\"";
00431 *ts <<
">\n";
00432 *ts <<
" " << todo->
priority() <<
"\n";
00433 *ts <<
" </td>\n";
00434
00435 *ts <<
" <td";
00436
if (completed) *ts <<
" class=\"done\"";
00437 *ts <<
">\n";
00438 *ts <<
" " << i18n(
"%1 %").arg(todo->
percentComplete()) <<
"\n";
00439 *ts <<
" </td>\n";
00440
00441
if (dueDateEnabled()) {
00442 *ts <<
" <td";
00443
if (completed) *ts <<
" class=\"done\"";
00444 *ts <<
">\n";
00445
if (todo->
hasDueDate()) {
00446 *ts <<
" " << todo->
dtDueDateStr() <<
"\n";
00447 }
else {
00448 *ts <<
" \n";
00449 }
00450 *ts <<
" </td>\n";
00451 }
00452
00453
if (categoriesTodoEnabled()) {
00454 *ts <<
" <td";
00455
if (completed) *ts <<
" class=\"done\"";
00456 *ts <<
">\n";
00457 formatHtmlCategories(ts,todo);
00458 *ts <<
" </td>\n";
00459 }
00460
00461
if (attendeesTodoEnabled()) {
00462 *ts <<
" <td";
00463
if (completed) *ts <<
" class=\"done\"";
00464 *ts <<
">\n";
00465 formatHtmlAttendees(ts,todo);
00466 *ts <<
" </td>\n";
00467 }
00468
00469 *ts <<
"</tr>\n";
00470 }
00471
00472
bool HtmlExport::checkSecrecy(
Incidence *incidence )
00473 {
00474
int secrecy = incidence->
secrecy();
00475
if ( secrecy == Incidence::SecrecyPublic ) {
00476
return true;
00477 }
00478
if ( secrecy == Incidence::SecrecyPrivate && !excludePrivateEventEnabled() ) {
00479
return true;
00480 }
00481
if ( secrecy == Incidence::SecrecyConfidential &&
00482 !excludeConfidentialEventEnabled() ) {
00483
return true;
00484 }
00485
return false;
00486 }
00487
00488
void HtmlExport::formatHtmlCategories (QTextStream *ts,
Incidence *event)
00489 {
00490
if (!event->
categoriesStr().isEmpty()) {
00491 *ts <<
" " << cleanChars(event->
categoriesStr()) <<
"\n";
00492 }
else {
00493 *ts <<
" \n";
00494 }
00495 }
00496
00497
void HtmlExport::formatHtmlAttendees (QTextStream *ts,
Incidence *event)
00498 {
00499
Attendee::List attendees = event->
attendees();
00500
if (attendees.count()) {
00501 *ts <<
"<em>";
00502
#ifndef KORG_NOKABC
00503
KABC::AddressBook *add_book = KABC::StdAddressBook::self();
00504 KABC::Addressee::List addressList;
00505 addressList = add_book->findByEmail(event->
organizer());
00506 KABC::Addressee o = addressList.first();
00507
if (!o.isEmpty() && addressList.size()<2) {
00508 *ts <<
"<a href=\"mailto:" << event->
organizer() <<
"\">";
00509 *ts << cleanChars(o.formattedName()) <<
"</a>\n";
00510 }
00511
else *ts << event->
organizer();
00512
#else
00513
*ts << event->
organizer();
00514
#endif
00515
*ts <<
"</em><br />";
00516 Attendee::List::ConstIterator it;
00517
for( it = attendees.begin(); it != attendees.end(); ++it ) {
00518
Attendee *a = *it;
00519
if (!a->
email().isEmpty()) {
00520 *ts <<
"<a href=\"mailto:" << a->
email();
00521 *ts <<
"\">" << cleanChars(a->
name()) <<
"</a>";
00522 }
00523
else {
00524 *ts <<
" " << cleanChars(a->
name());
00525 }
00526 *ts <<
"<br />" <<
"\n";
00527 }
00528 }
else {
00529 *ts <<
" \n";
00530 }
00531 }
00532
00533 QString HtmlExport::breakString(
const QString &text)
00534 {
00535
int number = text.contains(
"\n");
00536
if(number < 0) {
00537
return text;
00538 }
else {
00539 QString out;
00540 QString tmpText = text;
00541
int pos = 0;
00542 QString tmp;
00543
for(
int i=0;i<=number;i++) {
00544 pos = tmpText.find(
"\n");
00545 tmp = tmpText.left(pos);
00546 tmpText = tmpText.right(tmpText.length() - pos - 1);
00547 out += tmp +
"<br />";
00548 }
00549
return out;
00550 }
00551 }
00552
00553 QString HtmlExport::cleanChars(
const QString &text)
00554 {
00555 QString txt = text;
00556 txt = txt.replace(
"&",
"&" );
00557 txt = txt.replace(
"<",
"<" );
00558 txt = txt.replace(
">",
">" );
00559 txt = txt.replace(
"\"",
""" );
00560 txt = txt.replace(
"ä",
"ä" );
00561 txt = txt.replace(
"Ä",
"Ä" );
00562 txt = txt.replace(
"ö",
"ö" );
00563 txt = txt.replace(
"Ö",
"Ö" );
00564 txt = txt.replace(
"ü",
"ü" );
00565 txt = txt.replace(
"Ü",
"Ü" );
00566 txt = txt.replace(
"ß",
"ß" );
00567 txt = txt.replace(
"¤",
"€" );
00568 txt = txt.replace(
"é",
"é" );
00569
00570
return txt;
00571 }
00572
00573
void HtmlExport::setStyleSheet(
const QString &styleSheet )
00574 {
00575 mStyleSheet = styleSheet;
00576 }
00577
00578 QString HtmlExport::styleSheet()
00579 {
00580
if ( !mStyleSheet.isEmpty() )
return mStyleSheet;
00581
00582 QString css;
00583
00584
if ( QApplication::reverseLayout() ) {
00585 css +=
" body { background-color:white; color:black; direction: rtl }\n";
00586 css +=
" td { text-align:center; background-color:#eee }\n";
00587 css +=
" th { text-align:center; background-color:#228; color:white }\n";
00588 css +=
" td.sumdone { background-color:#ccc }\n";
00589 css +=
" td.done { background-color:#ccc }\n";
00590 css +=
" td.subhead { text-align:center; background-color:#ccf }\n";
00591 css +=
" td.datehead { text-align:center; background-color:#ccf }\n";
00592 css +=
" td.space { background-color:white }\n";
00593 css +=
" td.dateholiday { color:red }\n";
00594 }
else {
00595 css +=
" body { background-color:white; color:black }\n";
00596 css +=
" td { text-align:center; background-color:#eee }\n";
00597 css +=
" th { text-align:center; background-color:#228; color:white }\n";
00598 css +=
" td.sum { text-align:left }\n";
00599 css +=
" td.sumdone { text-align:left; background-color:#ccc }\n";
00600 css +=
" td.done { background-color:#ccc }\n";
00601 css +=
" td.subhead { text-align:center; background-color:#ccf }\n";
00602 css +=
" td.datehead { text-align:center; background-color:#ccf }\n";
00603 css +=
" td.space { background-color:white }\n";
00604 css +=
" td.date { text-align:left }\n";
00605 css +=
" td.dateholiday { text-align:left; color:red }\n";
00606 }
00607
00608
return css;
00609 }
00610
00611
00612
void HtmlExport::addHoliday( QDate date, QString name)
00613 {
00614 mHolidayMap[date] = name;
00615 }
00616