23 #include <tqapplication.h>
25 #include <tqtextstream.h>
26 #include <tqtextcodec.h>
29 #include <kcharsets.h>
30 #include <tdeglobal.h>
31 #include <tdelocale.h>
33 #include <kcalendarsystem.h>
36 #include <libkcal/event.h>
37 #include <libkcal/incidenceformatter.h>
38 #include <libkcal/todo.h>
41 #include <tdeabc/stdaddressbook.h>
43 #include "htmlexport.h"
44 #include "htmlexportsettings.h"
49 mCalendar( calendar ), mSettings( settings )
55 TQString fn( fileName );
56 if ( fn.isEmpty() && mSettings ) {
57 fn = mSettings->outputFile();
59 if ( !mSettings || fn.isEmpty() ) {
63 if ( !f.open(IO_WriteOnly)) {
67 bool success =
save(&ts);
74 if ( !mSettings )
return false;
75 ts->setEncoding( TQTextStream::UnicodeUTF8 );
78 *ts <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ";
79 *ts <<
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
81 *ts <<
"<html><head>" << endl;
82 *ts <<
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=";
83 *ts <<
"UTF-8\" />\n";
84 if ( !mSettings->pageTitle().isEmpty())
85 *ts <<
" <title>" << mSettings->pageTitle() <<
"</title>\n";
86 *ts <<
" <style type=\"text/css\">\n";
89 *ts <<
"</head><body>\n";
94 if ( mSettings->eventView() || mSettings->monthView() || mSettings->weekView() ) {
95 if (!mSettings->eventTitle().isEmpty())
96 *ts <<
"<h1>" << mSettings->eventTitle() <<
"</h1>\n";
99 if ( mSettings->weekView() )
100 createWeekView( ts );
102 if ( mSettings->monthView() )
103 createMonthView( ts );
105 if ( mSettings->eventView() )
106 createEventList( ts );
110 if ( mSettings->todoView() ) {
111 if ( !mSettings->todoListTitle().isEmpty())
112 *ts <<
"<h1>" << mSettings->todoListTitle() <<
"</h1>\n";
117 if ( mSettings->journalView() ) {
118 if ( !mSettings->journalTitle().isEmpty())
119 *ts <<
"<h1>" << mSettings->journalTitle() <<
"</h1>\n";
120 createJournalView(ts);
124 if ( mSettings->freeBusyView() ) {
125 if ( !mSettings->freeBusyTitle().isEmpty())
126 *ts <<
"<h1>" << mSettings->freeBusyTitle() <<
"</h1>\n";
127 createFreeBusyView(ts);
133 *ts <<
"</body></html>\n";
138 void HtmlExport::createMonthView(TQTextStream *ts)
140 TQDate start = fromDate();
141 start.setYMD( start.year(), start.month(), 1 );
143 TQDate end( start.year(), start.month(), start.daysInMonth() );
145 int startmonth = start.month();
146 int startyear = start.year();
148 while ( start < toDate() ) {
150 *ts <<
"<h2>" << (i18n(
"month_year",
"%1 %2").arg(TDEGlobal::locale()->calendar()->monthName(start))
151 .arg(start.year())) <<
"</h2>\n";
152 if ( TDEGlobal::locale()->weekStartDay() == 1 ) {
153 start = start.addDays(1 - start.dayOfWeek());
155 if (start.dayOfWeek() != 7) {
156 start = start.addDays(-start.dayOfWeek());
159 *ts <<
"<table border=\"1\">\n";
163 for(
int i=0; i<7; ++i) {
164 *ts <<
"<th>" << TDEGlobal::locale()->calendar()->weekDayName( start.addDays(i) ) <<
"</th>";
169 while (start <= end) {
171 for(
int i=0;i<7;++i) {
172 *ts <<
" <td valign=\"top\"><table border=\"0\">";
175 if (mHolidayMap.contains(start) || start.dayOfWeek() == 7) {
176 *ts <<
"class=\"dateholiday\"";
178 *ts <<
"class=\"date\"";
180 *ts <<
">" << TQString::number(start.day());
182 if (mHolidayMap.contains(start)) {
183 *ts <<
" <em>" << mHolidayMap[start] <<
"</em>";
186 *ts <<
"</td></tr><tr><td valign=\"top\">";
189 if ( start >= fromDate() && start <= toDate() ) {
193 if (events.count()) {
195 Event::List::ConstIterator it;
196 for( it = events.begin(); it != events.end(); ++it ) {
197 if ( checkSecrecy( *it ) ) {
198 createEvent( ts, *it, start,
false );
207 *ts <<
"</td></tr></table></td>\n";
208 start = start.addDays(1);
214 if ( startmonth > 12 ) {
218 start.setYMD( startyear, startmonth, 1 );
219 end.setYMD(start.year(),start.month(),start.daysInMonth());
223 void HtmlExport::createEventList (TQTextStream *ts)
226 *ts <<
"<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
228 *ts <<
" <th class=\"sum\">" << i18n(
"Start Time") <<
"</th>\n";
229 *ts <<
" <th>" << i18n(
"End Time") <<
"</th>\n";
230 *ts <<
" <th>" << i18n(
"Event") <<
"</th>\n";
231 if ( mSettings->eventLocation() ) {
232 *ts <<
" <th>" << i18n(
"Location") <<
"</th>\n";
235 if ( mSettings->eventCategories() ) {
236 *ts <<
" <th>" << i18n(
"Categories") <<
"</th>\n";
239 if ( mSettings->eventAttendees() ) {
240 *ts <<
" <th>" << i18n(
"Attendees") <<
"</th>\n";
246 for ( TQDate dt = fromDate(); dt <= toDate(); dt = dt.addDays(1) ) {
247 kdDebug(5850) <<
"Getting events for " << TQString(dt.toString()) << endl;
251 if (events.count()) {
252 Event::List::ConstIterator it;
254 for( it = events.begin(); it != events.end(); ++it ) {
255 if ( checkSecrecy( *it ) ) {
257 *ts <<
" <tr><td colspan=\"" << TQString::number(columns)
258 <<
"\" class=\"datehead\"><i>"
259 << TDEGlobal::locale()->formatDate(dt)
260 <<
"</i></td></tr>\n";
263 createEvent( ts, *it, dt );
272 void HtmlExport::createEvent (TQTextStream *ts,
Event *event,
273 TQDate date,
bool withDescription)
275 kdDebug(5850) <<
"HtmlExport::createEvent(): " <<
event->summary() << endl;
280 *ts <<
" <td> </td>\n";
282 *ts <<
" <td valign=\"top\">"
283 << IncidenceFormatter::timeToString( event->
dtStart(),
true )
287 *ts <<
" <td> </td>\n";
289 *ts <<
" <td valign=\"top\">"
290 << IncidenceFormatter::timeToString( event->
dtEnd(),
true )
294 *ts <<
" <td> </td><td> </td>\n";
297 *ts <<
" <td class=\"sum\">\n";
298 *ts <<
" <b>" << cleanChars(event->
summary()) <<
"</b>\n";
299 if ( withDescription && !event->
description().isEmpty() ) {
300 *ts <<
" <p>" << breakString( cleanChars( event->
description() ) ) <<
"</p>\n";
304 if ( mSettings->eventLocation() ) {
306 formatLocation( ts, event );
310 if ( mSettings->eventCategories() ) {
312 formatCategories( ts, event );
316 if ( mSettings->eventAttendees() ) {
318 formatAttendees( ts, event );
325 void HtmlExport::createTodoList ( TQTextStream *ts )
329 Todo::List::Iterator it = rawTodoList.begin();
330 while ( it != rawTodoList.end() ) {
335 if ( rawTodoList.find(
static_cast<Todo *
>( ev->
relatedTo() ) ) ==
336 rawTodoList.end() ) {
337 rawTodoList.append(
static_cast<Todo *
>( ev->
relatedTo() ) );
341 it = rawTodoList.find( subev );
348 for (
int i = 1; i <= 9; ++i ) {
349 for( it = rawTodoList.begin(); it != rawTodoList.end(); ++it ) {
350 if ( (*it)->priority() == i && checkSecrecy( *it ) ) {
351 todoList.append( *it );
355 for( it = rawTodoList.begin(); it != rawTodoList.end(); ++it ) {
356 if ( (*it)->priority() == 0 && checkSecrecy( *it ) ) {
357 todoList.append( *it );
362 *ts <<
"<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
364 *ts <<
" <th class=\"sum\">" << i18n(
"Task") <<
"</th>\n";
365 *ts <<
" <th>" << i18n(
"Priority") <<
"</th>\n";
366 *ts <<
" <th>" << i18n(
"Completed") <<
"</th>\n";
367 if ( mSettings->taskDueDate() ) {
368 *ts <<
" <th>" << i18n(
"Due Date") <<
"</th>\n";
371 if ( mSettings->taskLocation() ) {
372 *ts <<
" <th>" << i18n(
"Location") <<
"</th>\n";
375 if ( mSettings->taskCategories() ) {
376 *ts <<
" <th>" << i18n(
"Categories") <<
"</th>\n";
379 if ( mSettings->taskAttendees() ) {
380 *ts <<
" <th>" << i18n(
"Attendees") <<
"</th>\n";
386 for( it = todoList.begin(); it != todoList.end(); ++it ) {
387 if ( !(*it)->relatedTo() ) createTodo( ts, *it );
391 for( it = todoList.begin(); it != todoList.end(); ++it ) {
393 if (relations.count()) {
396 *ts <<
" <td class=\"subhead\" colspan=";
397 *ts <<
"\"" << TQString::number(columns) <<
"\"";
398 *ts <<
"><a name=\"sub" << (*it)->uid() <<
"\"></a>"
399 << i18n(
"Sub-Tasks of: ") <<
"<a href=\"#"
400 << (*it)->uid() <<
"\"><b>" << cleanChars( (*it)->summary())
401 <<
"</b></a></td>\n";
407 for (
int i = 1; i <= 9; ++i ) {
408 Incidence::List::ConstIterator it2;
409 for( it2 = relations.begin(); it2 != relations.end(); ++it2 ) {
410 Todo *ev3 =
dynamic_cast<Todo *
>( *it2 );
411 if ( ev3 && ev3->
priority() == i ) sortedList.append( ev3 );
414 Incidence::List::ConstIterator it2;
415 for( it2 = relations.begin(); it2 != relations.end(); ++it2 ) {
416 Todo *ev3 =
dynamic_cast<Todo *
>( *it2 );
417 if ( ev3 && ev3->
priority() == 0 ) sortedList.append( ev3 );
420 Todo::List::ConstIterator it3;
421 for( it3 = sortedList.begin(); it3 != sortedList.end(); ++it3 ) {
422 createTodo( ts, *it3 );
430 void HtmlExport::createTodo (TQTextStream *ts,
Todo *todo)
432 kdDebug(5850) <<
"HtmlExport::createTodo()" << endl;
439 *ts <<
" <td class=\"sum";
440 if (completed) *ts <<
"done";
442 *ts <<
" <a name=\"" << todo->
uid() <<
"\"></a>\n";
443 *ts <<
" <b>" << cleanChars(todo->
summary()) <<
"</b>\n";
445 *ts <<
" <p>" << breakString(cleanChars(todo->
description())) <<
"</p>\n";
447 if (relations.count()) {
448 *ts <<
" <div align=\"right\"><a href=\"#sub" << todo->
uid()
449 <<
"\">" << i18n(
"Sub-Tasks") <<
"</a></div>\n";
454 if (completed) *ts <<
" class=\"done\"";
456 *ts <<
" " << todo->
priority() <<
"\n";
460 if (completed) *ts <<
" class=\"done\"";
465 if ( mSettings->taskDueDate() ) {
467 if (completed) *ts <<
" class=\"done\"";
470 *ts <<
" " << IncidenceFormatter::dateToString( todo->
dtDue(
true ) ) <<
"\n";
477 if ( mSettings->taskLocation() ) {
479 if (completed) *ts <<
" class=\"done\"";
481 formatLocation(ts,todo);
485 if ( mSettings->taskCategories() ) {
487 if (completed) *ts <<
" class=\"done\"";
489 formatCategories(ts,todo);
493 if ( mSettings->taskAttendees() ) {
495 if (completed) *ts <<
" class=\"done\"";
497 formatAttendees(ts,todo);
504 void HtmlExport::createWeekView( TQTextStream * )
509 void HtmlExport::createJournalView( TQTextStream * )
515 void HtmlExport::createFreeBusyView( TQTextStream * )
520 bool HtmlExport::checkSecrecy(
Incidence *incidence )
522 int secrecy = incidence->
secrecy();
523 if ( secrecy == Incidence::SecrecyPublic ) {
526 if ( secrecy == Incidence::SecrecyPrivate && !mSettings->excludePrivate() ) {
529 if ( secrecy == Incidence::SecrecyConfidential &&
530 !mSettings->excludeConfidential() ) {
536 void HtmlExport::formatLocation (TQTextStream *ts,
Incidence *event)
539 *ts <<
" " << cleanChars(event->
location()) <<
"\n";
545 void HtmlExport::formatCategories (TQTextStream *ts,
Incidence *event)
554 void HtmlExport::formatAttendees( TQTextStream *ts,
Incidence *event )
557 if (attendees.count()) {
560 TDEABC::AddressBook *add_book = TDEABC::StdAddressBook::self(
true );
561 TDEABC::Addressee::List addressList;
562 addressList = add_book->findByEmail(event->organizer().email());
563 TDEABC::Addressee o = addressList.first();
564 if (!o.isEmpty() && addressList.size()<2) {
565 *ts <<
"<a href=\"mailto:" <<
event->organizer().email() <<
"\">";
566 *ts << cleanChars(o.formattedName()) <<
"</a>\n";
568 else *ts <<
event->organizer().fullName();
570 *ts <<
event->organizer().fullName();
572 *ts <<
"</em><br />";
573 Attendee::List::ConstIterator it;
574 for( it = attendees.begin(); it != attendees.end(); ++it ) {
576 if (!a->email().isEmpty()) {
577 *ts <<
"<a href=\"mailto:" << a->email();
578 *ts <<
"\">" << cleanChars(a->name()) <<
"</a>";
581 *ts <<
" " << cleanChars(a->name());
583 *ts <<
"<br />" <<
"\n";
590 TQString HtmlExport::breakString(
const TQString &text)
592 int number = text.contains(
"\n");
597 TQString tmpText = text;
600 for(
int i=0;i<=number;i++) {
601 pos = tmpText.find(
"\n");
602 tmp = tmpText.left(pos);
603 tmpText = tmpText.right(tmpText.length() - pos - 1);
604 out += tmp +
"<br />";
610 void HtmlExport::createFooter( TQTextStream *ts )
613 TQString trailer = i18n(
"This page was created ");
619 if (!mSettings->eMail().isEmpty()) {
620 if (!mSettings->name().isEmpty())
621 trailer += i18n(
"by <a href=\"mailto:%1\">%2</a> ").arg( mSettings->eMail() ).arg( mSettings->name() );
623 trailer += i18n(
"by <a href=\"mailto:%1\">%2</a> ").arg( mSettings->eMail() ).arg( mSettings->eMail() );
625 if (!mSettings->name().isEmpty())
626 trailer += i18n(
"by %1 ").arg( mSettings->name() );
628 if (!mSettings->creditName().isEmpty()) {
629 if (!mSettings->creditURL().isEmpty())
630 trailer += i18n(
"with <a href=\"%1\">%2</a>")
631 .arg( mSettings->creditURL() )
632 .arg( mSettings->creditName() );
634 trailer += i18n(
"with %1").arg( mSettings->creditName() );
636 *ts <<
"<p>" << trailer <<
"</p>\n";
640 TQString HtmlExport::cleanChars(
const TQString &text)
643 txt = txt.replace(
"&",
"&" );
644 txt = txt.replace(
"<",
"<" );
645 txt = txt.replace(
">",
">" );
646 txt = txt.replace(
"\"",
""" );
647 txt = txt.replace( TQString::fromUtf8(
"ä"),
"ä" );
648 txt = txt.replace( TQString::fromUtf8(
"á"),
"á" );
649 txt = txt.replace( TQString::fromUtf8(
"à"),
"à" );
650 txt = txt.replace( TQString::fromUtf8(
"â"),
"â" );
651 txt = txt.replace( TQString::fromUtf8(
"Ä"),
"Ä" );
652 txt = txt.replace( TQString::fromUtf8(
"ó"),
"ó" );
653 txt = txt.replace( TQString::fromUtf8(
"ô"),
"ô" );
654 txt = txt.replace( TQString::fromUtf8(
"ö"),
"ö" );
655 txt = txt.replace( TQString::fromUtf8(
"Ö"),
"Ö" );
656 txt = txt.replace( TQString::fromUtf8(
"ü"),
"ü" );
657 txt = txt.replace( TQString::fromUtf8(
"Ü"),
"Ü" );
658 txt = txt.replace( TQString::fromUtf8(
"ß"),
"ß" );
659 txt = txt.replace( TQString::fromUtf8(
"€"),
"€" );
660 txt = txt.replace( TQString::fromUtf8(
"é"),
"é" );
661 txt = txt.replace( TQString::fromUtf8(
"ë"),
"ë" );
662 txt = txt.replace( TQString::fromUtf8(
"è"),
"è" );
663 txt = txt.replace( TQString::fromUtf8(
"ñ"),
"ñ" );
664 txt = txt.replace( TQString::fromUtf8(
"ç"),
"ç" );
669 TQString HtmlExport::styleSheet()
const
671 if ( !mSettings->styleSheet().isEmpty() )
672 return mSettings->styleSheet();
676 if ( TQApplication::reverseLayout() ) {
677 css +=
" body { background-color:white; color:black; direction: rtl }\n";
678 css +=
" td { text-align:center; background-color:#eee }\n";
679 css +=
" th { text-align:center; background-color:#228; color:white }\n";
680 css +=
" td.sumdone { background-color:#ccc }\n";
681 css +=
" td.done { background-color:#ccc }\n";
682 css +=
" td.subhead { text-align:center; background-color:#ccf }\n";
683 css +=
" td.datehead { text-align:center; background-color:#ccf }\n";
684 css +=
" td.space { background-color:white }\n";
685 css +=
" td.dateholiday { color:red }\n";
687 css +=
" body { background-color:white; color:black }\n";
688 css +=
" td { text-align:center; background-color:#eee }\n";
689 css +=
" th { text-align:center; background-color:#228; color:white }\n";
690 css +=
" td.sum { text-align:left }\n";
691 css +=
" td.sumdone { text-align:left; background-color:#ccc }\n";
692 css +=
" td.done { background-color:#ccc }\n";
693 css +=
" td.subhead { text-align:center; background-color:#ccf }\n";
694 css +=
" td.datehead { text-align:center; background-color:#ccf }\n";
695 css +=
" td.space { background-color:white }\n";
696 css +=
" td.date { text-align:left }\n";
697 css +=
" td.dateholiday { text-align:left; color:red }\n";
704 void HtmlExport::addHoliday(
const TQDate &date,
const TQString &name)
706 if ( mHolidayMap[date].isEmpty() ) {
707 mHolidayMap[date] = name;
709 mHolidayMap[date] = i18n(
"list of holidays",
"%1, %2").arg(mHolidayMap[date]).arg(name);
713 TQDate HtmlExport::fromDate()
const
715 return mSettings->dateStart().date();
718 TQDate HtmlExport::toDate()
const
720 return mSettings->dateEnd().date();