23 #include "htmlexport.h"
24 #include "htmlexportsettings.h"
30 #include "kabc/stdaddressbook.h"
34 #include <klocalizedstring.h>
36 #include <kcalendarsystem.h>
38 #include <QtCore/QFile>
39 #include <QtCore/QTextStream>
40 #include <QtCore/QTextCodec>
41 #include <QtCore/QRegExp>
42 #include <QtCore/QMap>
43 #include <QApplication>
50 class KCal::HtmlExport::Private
53 Private(
Calendar *calendar, HTMLExportSettings *settings )
54 : mCalendar( calendar ),
59 HTMLExportSettings *mSettings;
65 : d( new Private( calendar, settings ) )
69 HtmlExport::~HtmlExport()
77 if ( fn.
isEmpty() && d->mSettings ) {
78 fn = d->mSettings->outputFile();
80 if ( !d->mSettings || fn.
isEmpty() ) {
84 if ( !f.
open( QIODevice::WriteOnly ) ) {
88 bool success =
save( &ts );
95 if ( !d->mSettings ) {
100 *ts <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ";
101 *ts <<
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl;
103 *ts <<
"<html><head>" << endl;
104 *ts <<
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=";
105 *ts <<
"UTF-8\" />" << endl;
106 if ( !d->mSettings->pageTitle().isEmpty() ) {
107 *ts <<
" <title>" << d->mSettings->pageTitle() <<
"</title>" << endl;
109 *ts <<
" <style type=\"text/css\">" << endl;
111 *ts <<
" </style>" << endl;
112 *ts <<
"</head><body>" << endl;
117 if ( d->mSettings->eventView() || d->mSettings->monthView() || d->mSettings->weekView() ) {
118 if ( !d->mSettings->eventTitle().isEmpty() ) {
119 *ts <<
"<h1>" << d->mSettings->eventTitle() <<
"</h1>" << endl;
123 if ( d->mSettings->weekView() ) {
124 createWeekView( ts );
127 if ( d->mSettings->monthView() ) {
128 createMonthView( ts );
131 if ( d->mSettings->eventView() ) {
132 createEventList( ts );
137 if ( d->mSettings->todoView() ) {
138 if ( !d->mSettings->todoListTitle().isEmpty() ) {
139 *ts <<
"<h1>" << d->mSettings->todoListTitle() <<
"</h1>" << endl;
141 createTodoList( ts );
145 if ( d->mSettings->journalView() ) {
146 if ( !d->mSettings->journalTitle().isEmpty() ) {
147 *ts <<
"<h1>" << d->mSettings->journalTitle() <<
"</h1>" << endl;
149 createJournalView( ts );
153 if ( d->mSettings->freeBusyView() ) {
154 if ( !d->mSettings->freeBusyTitle().isEmpty() ) {
155 *ts <<
"<h1>" << d->mSettings->freeBusyTitle() <<
"</h1>" << endl;
157 createFreeBusyView( ts );
163 *ts <<
"</body></html>" << endl;
168 void HtmlExport::createMonthView(
QTextStream *ts )
170 QDate start = fromDate();
175 int startmonth = start.
month();
176 int startyear = start.
year();
178 while ( start < toDate() ) {
181 QString hMon = hDate.toString(
"MMMM" );
182 QString hYear = hDate.toString(
"yyyy" );
184 << i18nc(
"@title month and year",
"%1 %2", hMon, hYear )
186 if ( KGlobal::locale()->weekStartDay() == 1 ) {
193 *ts <<
"<table border=\"1\">" << endl;
197 for (
int i=0; i < 7; ++i ) {
198 *ts <<
"<th>" << KGlobal::locale()->calendar()->weekDayName( start.
addDays(i) ) <<
"</th>";
200 *ts <<
"</tr>" << endl;
203 while ( start <= end ) {
204 *ts <<
" <tr>" << endl;
205 for (
int i=0; i < 7; ++i ) {
206 *ts <<
" <td valign=\"top\"><table border=\"0\">";
209 if ( d->mHolidayMap.contains( start ) || start.
dayOfWeek() == 7 ) {
210 *ts <<
"class=\"dateholiday\"";
212 *ts <<
"class=\"date\"";
216 if ( d->mHolidayMap.contains( start ) ) {
217 *ts <<
" <em>" << d->mHolidayMap[start] <<
"</em>";
220 *ts <<
"</td></tr><tr><td valign=\"top\">";
223 if ( start >= fromDate() && start <= toDate() ) {
224 Event::List events = d->mCalendar->events( start, d->mCalendar->timeSpec(),
226 SortDirectionAscending );
227 if ( events.
count() ) {
231 if ( checkSecrecy( *it ) ) {
232 createEvent( ts, *it, start,
false );
241 *ts <<
"</td></tr></table></td>" << endl;
244 *ts <<
" </tr>" << endl;
246 *ts <<
"</table>" << endl;
248 if ( startmonth > 12 ) {
252 start.
setYMD( startyear, startmonth, 1 );
257 void HtmlExport::createEventList(
QTextStream *ts )
260 *ts <<
"<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">" << endl;
261 *ts <<
" <tr>" << endl;
262 *ts <<
" <th class=\"sum\">" << i18nc(
"@title:column event start time",
263 "Start Time" ) <<
"</th>" << endl;
264 *ts <<
" <th>" << i18nc(
"@title:column event end time",
265 "End Time" ) <<
"</th>" << endl;
266 *ts <<
" <th>" << i18nc(
"@title:column event description",
267 "Event" ) <<
"</th>" << endl;
268 if ( d->mSettings->eventLocation() ) {
269 *ts <<
" <th>" << i18nc(
"@title:column event location",
270 "Location" ) <<
"</th>" << endl;
273 if ( d->mSettings->eventCategories() ) {
274 *ts <<
" <th>" << i18nc(
"@title:column event categories",
275 "Categories" ) <<
"</th>" << endl;
278 if ( d->mSettings->eventAttendees() ) {
279 *ts <<
" <th>" << i18nc(
"@title:column event attendees",
280 "Attendees" ) <<
"</th>" << endl;
284 *ts <<
" </tr>" << endl;
286 for (
QDate dt = fromDate(); dt <= toDate(); dt = dt.addDays(1) ) {
287 kDebug() <<
"Getting events for" << dt.toString();
288 Event::List events = d->mCalendar->events( dt, d->mCalendar->timeSpec(),
290 SortDirectionAscending );
291 if ( events.
count() ) {
293 <<
"\" class=\"datehead\"><i>"
294 << KGlobal::locale()->formatDate( dt )
295 <<
"</i></td></tr>" << endl;
299 if ( checkSecrecy( *it ) ) {
300 createEvent( ts, *it, dt );
306 *ts <<
"</table>" << endl;
310 QDate date,
bool withDescription )
312 kDebug() <<
event->summary();
313 *ts <<
" <tr>" << endl;
316 if ( event->
isMultiDay( d->mCalendar->timeSpec() ) && ( event->
dtStart().date() != date ) ) {
317 *ts <<
" <td> </td>" << endl;
319 *ts <<
" <td valign=\"top\">"
323 if ( event->
isMultiDay( d->mCalendar->timeSpec() ) && ( event->
dtEnd().date() != date ) ) {
324 *ts <<
" <td> </td>" << endl;
326 *ts <<
" <td valign=\"top\">"
331 *ts <<
" <td> </td><td> </td>" << endl;
334 *ts <<
" <td class=\"sum\">" << endl;
335 *ts <<
" <b>" << cleanChars( event->
summary() ) <<
"</b>" << endl;
337 *ts <<
" <p>" << breakString( cleanChars( event->
description() ) ) <<
"</p>" << endl;
339 *ts <<
" </td>" << endl;
341 if ( d->mSettings->eventLocation() ) {
342 *ts <<
" <td>" << endl;
343 formatLocation( ts, event );
344 *ts <<
" </td>" << endl;
347 if ( d->mSettings->eventCategories() ) {
348 *ts <<
" <td>" << endl;
349 formatCategories( ts, event );
350 *ts <<
" </td>" << endl;
353 if ( d->mSettings->eventAttendees() ) {
354 *ts <<
" <td>" << endl;
355 formatAttendees( ts, event );
356 *ts <<
" </td>" << endl;
359 *ts <<
" </tr>" << endl;
362 void HtmlExport::createTodoList (
QTextStream *ts )
364 Todo::List rawTodoList = d->mCalendar->todos();
367 while ( index < rawTodoList.
count() ) {
368 Todo *ev = rawTodoList[ index ];
377 index = rawTodoList.
indexOf( subev );
385 for (
int i = 1; i <= 9; ++i ) {
387 if ( (*it)->priority() == i && checkSecrecy( *it ) ) {
393 if ( (*it)->priority() == 0 && checkSecrecy( *it ) ) {
399 *ts <<
"<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">" << endl;
400 *ts <<
" <tr>" << endl;
401 *ts <<
" <th class=\"sum\">" << i18nc(
"@title:column",
"To-do" ) <<
"</th>" << endl;
402 *ts <<
" <th>" << i18nc(
"@title:column to-do priority",
"Priority" ) <<
"</th>" << endl;
403 *ts <<
" <th>" << i18nc(
"@title:column to-do percent completed",
404 "Completed" ) <<
"</th>" << endl;
405 if ( d->mSettings->taskDueDate() ) {
406 *ts <<
" <th>" << i18nc(
"@title:column to-do due date",
"Due Date" ) <<
"</th>" << endl;
409 if ( d->mSettings->taskLocation() ) {
410 *ts <<
" <th>" << i18nc(
"@title:column to-do location",
"Location" ) <<
"</th>" << endl;
413 if ( d->mSettings->taskCategories() ) {
414 *ts <<
" <th>" << i18nc(
"@title:column to-do categories",
"Categories" ) <<
"</th>" << endl;
417 if ( d->mSettings->taskAttendees() ) {
418 *ts <<
" <th>" << i18nc(
"@title:column to-do attendees",
"Attendees" ) <<
"</th>" << endl;
421 *ts <<
" </tr>" << endl;
425 if ( !(*it)->relatedTo() ) {
426 createTodo( ts, *it );
433 if ( relations.
count() ) {
435 *ts <<
" <tr>" << endl;
436 *ts <<
" <td class=\"subhead\" colspan=";
438 *ts <<
"><a name=\"sub" << (*it)->uid() <<
"\"></a>"
439 << i18nc(
"@title:column sub-to-dos of the parent to-do",
440 "Sub-To-dos of: " ) <<
"<a href=\"#"
441 << (*it)->uid() <<
"\"><b>" << cleanChars( (*it)->summary() )
442 <<
"</b></a></td>" << endl;
443 *ts <<
" </tr>" << endl;
448 for (
int i = 1; i <= 9; ++i ) {
451 Todo *ev3 =
dynamic_cast<Todo *
>( *it2 );
452 if ( ev3 && ev3->
priority() == i ) {
459 Todo *ev3 =
dynamic_cast<Todo *
>( *it2 );
460 if ( ev3 && ev3->
priority() == 0 ) {
467 createTodo( ts, *it3 );
472 *ts <<
"</table>" << endl;
482 *ts <<
"<tr>" << endl;
484 *ts <<
" <td class=\"sum";
485 if (completed) *ts <<
"done";
486 *ts <<
"\">" << endl;
487 *ts <<
" <a name=\"" << todo->
uid() <<
"\"></a>" << endl;
488 *ts <<
" <b>" << cleanChars( todo->
summary() ) <<
"</b>" << endl;
490 *ts <<
" <p>" << breakString( cleanChars( todo->
description() ) ) <<
"</p>" << endl;
492 if ( relations.
count() ) {
493 *ts <<
" <div align=\"right\"><a href=\"#sub" << todo->
uid()
494 <<
"\">" << i18nc(
"@title:column sub-to-dos of the parent to-do",
495 "Sub-To-dos" ) <<
"</a></div>" << endl;
497 *ts <<
" </td>" << endl;
501 *ts <<
" class=\"done\"";
504 *ts <<
" " << todo->
priority() << endl;
505 *ts <<
" </td>" << endl;
509 *ts <<
" class=\"done\"";
512 *ts <<
" " << i18nc(
"@info/plain to-do percent complete",
514 *ts <<
" </td>" << endl;
516 if ( d->mSettings->taskDueDate() ) {
519 *ts <<
" class=\"done\"";
525 *ts <<
" " << endl;
527 *ts <<
" </td>" << endl;
530 if ( d->mSettings->taskLocation() ) {
533 *ts <<
" class=\"done\"";
536 formatLocation( ts, todo );
537 *ts <<
" </td>" << endl;
540 if ( d->mSettings->taskCategories() ) {
543 *ts <<
" class=\"done\"";
546 formatCategories( ts, todo );
547 *ts <<
" </td>" << endl;
550 if ( d->mSettings->taskAttendees() ) {
553 *ts <<
" class=\"done\"";
556 formatAttendees( ts, todo );
557 *ts <<
" </td>" << endl;
560 *ts <<
"</tr>" << endl;
569 void HtmlExport::createJournalView(
QTextStream *ts )
576 void HtmlExport::createFreeBusyView(
QTextStream *ts )
582 bool HtmlExport::checkSecrecy(
Incidence *incidence )
584 int secrecy = incidence->
secrecy();
592 !d->mSettings->excludeConfidential() ) {
601 *ts <<
" " << cleanChars( incidence->
location() ) << endl;
603 *ts <<
" " << endl;
610 *ts <<
" " << cleanChars( incidence->
categoriesStr() ) << endl;
612 *ts <<
" " << endl;
619 if ( attendees.
count() ) {
621 #if !defined(KORG_NOKABC) && !defined(KDEPIM_NO_KRESOURCES)
622 KABC::AddressBook *add_book = KABC::StdAddressBook::self(
true );
623 KABC::Addressee::List addressList;
624 addressList = add_book->findByEmail( incidence->
organizer().
email() );
625 if ( !addressList.isEmpty() ) {
626 KABC::Addressee o = addressList.first();
627 if ( !o.isEmpty() && addressList.size() < 2 ) {
628 *ts <<
"<a href=\"mailto:" << incidence->
organizer().
email() <<
"\">";
629 *ts << cleanChars( o.formattedName() ) <<
"</a>" << endl;
637 *ts <<
"</em><br />";
642 *ts <<
"<a href=\"mailto:" << a->
email();
643 *ts <<
"\">" << cleanChars( a->
name() ) <<
"</a>";
645 *ts <<
" " << cleanChars( a->
name() );
647 *ts <<
"<br />" << endl;
650 *ts <<
" " << endl;
656 int number = text.
count(
"\n" );
664 for (
int i = 0; i <= number; ++i ) {
666 tmp = tmpText.
left( pos );
667 tmpText = tmpText.
right( tmpText.
length() - pos - 1 );
668 out += tmp +
"<br />";
677 QString trailer = i18nc(
"@info/plain",
"This page was created " );
683 if ( !d->mSettings->eMail().isEmpty() ) {
684 if ( !d->mSettings->name().isEmpty() ) {
685 trailer += i18nc(
"@info/plain page creator email link with name",
686 "by <link url='mailto:%1'>%2</link> ",
687 d->mSettings->eMail(), d->mSettings->name() );
689 trailer += i18nc(
"@info/plain page creator email link",
690 "by <link url='mailto:%1'>%2</link> ",
691 d->mSettings->eMail(), d->mSettings->eMail() );
694 if ( !d->mSettings->name().isEmpty() ) {
695 trailer += i18nc(
"@info/plain page creator name only",
696 "by %1 ", d->mSettings->name() );
699 if ( !d->mSettings->creditName().isEmpty() ) {
700 if ( !d->mSettings->creditURL().isEmpty() ) {
701 trailer += i18nc(
"@info/plain page credit with name and link",
702 "with <link url='%1'>%2</link>",
703 d->mSettings->creditURL(), d->mSettings->creditName() );
705 trailer += i18nc(
"@info/plain page credit name only",
706 "with %1", d->mSettings->creditName() );
709 *ts <<
"<p>" << trailer <<
"</p>" << endl;
715 txt = txt.
replace(
'&',
"&" );
716 txt = txt.
replace(
'<',
"<" );
717 txt = txt.
replace(
'>',
">" );
718 txt = txt.
replace(
'\"',
""" );
732 QString HtmlExport::styleSheet()
const
734 if ( !d->mSettings->styleSheet().isEmpty() ) {
735 return d->mSettings->styleSheet();
741 css +=
" body { background-color:white; color:black; direction: rtl }\n";
742 css +=
" td { text-align:center; background-color:#eee }\n";
743 css +=
" th { text-align:center; background-color:#228; color:white }\n";
744 css +=
" td.sumdone { background-color:#ccc }\n";
745 css +=
" td.done { background-color:#ccc }\n";
746 css +=
" td.subhead { text-align:center; background-color:#ccf }\n";
747 css +=
" td.datehead { text-align:center; background-color:#ccf }\n";
748 css +=
" td.space { background-color:white }\n";
749 css +=
" td.dateholiday { color:red }\n";
751 css +=
" body { background-color:white; color:black }\n";
752 css +=
" td { text-align:center; background-color:#eee }\n";
753 css +=
" th { text-align:center; background-color:#228; color:white }\n";
754 css +=
" td.sum { text-align:left }\n";
755 css +=
" td.sumdone { text-align:left; background-color:#ccc }\n";
756 css +=
" td.done { background-color:#ccc }\n";
757 css +=
" td.subhead { text-align:center; background-color:#ccf }\n";
758 css +=
" td.datehead { text-align:center; background-color:#ccf }\n";
759 css +=
" td.space { background-color:white }\n";
760 css +=
" td.date { text-align:left }\n";
761 css +=
" td.dateholiday { text-align:left; color:red }\n";
767 void HtmlExport::addHoliday(
const QDate &date,
const QString &name )
769 if ( d->mHolidayMap[date].isEmpty() ) {
770 d->mHolidayMap[date] = name;
772 d->mHolidayMap[date] = i18nc(
"@info/plain holiday by date and name",
773 "%1, %2", d->mHolidayMap[date], name );
777 QDate HtmlExport::fromDate()
const
779 return d->mSettings->dateStart().date();
782 QDate HtmlExport::toDate()
const
784 return d->mSettings->dateEnd().date();
void setCodec(QTextCodec *codec)
QString description() const
Returns the incidence description.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString email() const
Returns the email address for this person.
Incidence * relatedTo() const
Returns a pointer for the incidence that is related to this one.
const Attendee::List & attendees() const
Returns a list of incidence attendees.
Provides a To-do in the sense of RFC2445.
Represents the main calendar class.
HtmlExport(Calendar *calendar, HTMLExportSettings *settings)
Create new HTML exporter for calendar.
virtual KDateTime dtStart() const
Returns an incidence's starting date/time as a KDateTime.
Represents information related to an attendee of an Calendar Incidence, typically a meeting or task (...
This class provides an Event in the sense of RFC2445.
QString categoriesStr() const
Returns the incidence categories as a comma separated string.
QString uid() const
Returns the unique id (uid) for the incidence.
KDateTime dtDue(bool first=false) const
Returns due date and time.
int indexOf(const T &value, int from) const
bool isCompleted() const
Returns true if the todo is 100% completed, otherwise return false.
bool isMultiDay(const KDateTime::Spec &spec=KDateTime::Spec()) const
Returns true if the event spans multiple days, otherwise return false.
QString number(int n, int base)
int count(const T &value) const
void append(const T &value)
QString fromUtf8(const char *str, int size)
bool setYMD(int y, int m, int d)
bool allDay() const
Returns true or false depending on whether the incidence is all-day.
virtual QByteArray type() const =0
Prints the type of Incidence as a string.
This file is part of the API for handling calendar data and defines the Todo class.
This file is part of the API for handling calendar data and defines the Calendar class.
QString name() const
Returns the person name string.
Person organizer() const
Returns the Person associated with this incidence.
Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar component...
This class provides a template for lists of pointers.
bool hasDueDate() const
Returns true if the todo has a due date, otherwise return false.
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString right(int n) const
bool contains(const T &value) const
QString & replace(int position, int n, QChar after)
Secret to the owner and some others.
This file is part of the API for handling calendar data and defines the Event class.
QString fullName() const
Returns the full name of this person.
QString left(int n) const
int percentComplete() const
Returns what percentage of the to-do is completed.
bool save(const QString &fileName=QString())
Writes out the calendar in HTML format.
int priority() const
Returns the incidence priority.
QDate addDays(int ndays) const
QString location() const
Returns the incidence location.
const_iterator constEnd() const
const_iterator constBegin() const
Secrecy secrecy() const
Returns the incidence Secrecy.
Incidence::List relations() const
Returns a list of all incidences related to this one.
virtual KDateTime dtEnd() const
Returns the event end date and time.
QString summary() const
Returns the incidence summary.