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