libkcal

htmlexport.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <tqapplication.h>
00024 #include <tqfile.h>
00025 #include <tqtextstream.h>
00026 #include <tqtextcodec.h>
00027 #include <tqregexp.h>
00028 
00029 #include <kcharsets.h>
00030 #include <tdeglobal.h>
00031 #include <tdelocale.h>
00032 #include <kdebug.h>
00033 #include <kcalendarsystem.h>
00034 
00035 #include <libkcal/calendar.h>
00036 #include <libkcal/event.h>
00037 #include <libkcal/incidenceformatter.h>
00038 #include <libkcal/todo.h>
00039 
00040 #ifndef KORG_NOKABC
00041  #include <tdeabc/stdaddressbook.h>
00042 #endif
00043 #include "htmlexport.h"
00044 #include "htmlexportsettings.h"
00045 
00046 using namespace KCal;
00047 
00048 HtmlExport::HtmlExport( Calendar *calendar, HTMLExportSettings *settings ) :
00049   mCalendar( calendar ), mSettings( settings )
00050 {
00051 }
00052 
00053 bool HtmlExport::save( const TQString &fileName )
00054 {
00055   TQString fn( fileName );
00056   if ( fn.isEmpty() && mSettings ) {
00057     fn = mSettings->outputFile();
00058   }
00059   if ( !mSettings || fn.isEmpty() ) {
00060     return false;
00061   }
00062   TQFile f( fileName );
00063   if ( !f.open(IO_WriteOnly)) {
00064     return false;
00065   }
00066   TQTextStream ts(&f);
00067   bool success = save(&ts);
00068   f.close();
00069   return success;
00070 }
00071 
00072 bool HtmlExport::save(TQTextStream *ts)
00073 {
00074   if ( !mSettings ) return false;
00075   ts->setEncoding( TQTextStream::UnicodeUTF8 );
00076 
00077   // Write HTML header
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 ( !mSettings->pageTitle().isEmpty())
00085     *ts << "  <title>" << mSettings->pageTitle() << "</title>\n";
00086   *ts << "  <style type=\"text/css\">\n";
00087   *ts << styleSheet();
00088   *ts << "  </style>\n";
00089   *ts << "</head><body>\n";
00090 
00091   // FIXME: Write header
00092   // (Heading, Calendar-Owner, Calendar-Date, ...)
00093 
00094   if ( mSettings->eventView() || mSettings->monthView() || mSettings->weekView() ) {
00095     if (!mSettings->eventTitle().isEmpty())
00096       *ts << "<h1>" << mSettings->eventTitle() << "</h1>\n";
00097 
00098     // Write Week View
00099     if ( mSettings->weekView() )
00100       createWeekView( ts );
00101     // Write Month View
00102     if ( mSettings->monthView() )
00103       createMonthView( ts );
00104     // Write Event List
00105     if ( mSettings->eventView() )
00106       createEventList( ts );
00107   }
00108 
00109   // Write Todo List
00110   if ( mSettings->todoView() ) {
00111     if ( !mSettings->todoListTitle().isEmpty())
00112       *ts << "<h1>" << mSettings->todoListTitle() << "</h1>\n";
00113     createTodoList(ts);
00114   }
00115 
00116   // Write Journals
00117   if ( mSettings->journalView() ) {
00118     if ( !mSettings->journalTitle().isEmpty())
00119       *ts << "<h1>" << mSettings->journalTitle() << "</h1>\n";
00120     createJournalView(ts);
00121   }
00122 
00123   // Write Free/Busy
00124   if ( mSettings->freeBusyView() ) {
00125     if ( !mSettings->freeBusyTitle().isEmpty())
00126       *ts << "<h1>" << mSettings->freeBusyTitle() << "</h1>\n";
00127     createFreeBusyView(ts);
00128   }
00129 
00130   createFooter( ts );
00131 
00132   // Write HTML trailer
00133   *ts << "</body></html>\n";
00134 
00135   return true;
00136 }
00137 
00138 void HtmlExport::createMonthView(TQTextStream *ts)
00139 {
00140   TQDate start = fromDate();
00141   start.setYMD( start.year(), start.month(), 1 );  // go back to first day in month
00142 
00143   TQDate end( start.year(), start.month(), start.daysInMonth() );
00144 
00145   int startmonth = start.month();
00146   int startyear = start.year();
00147 
00148   while ( start < toDate() ) {
00149     // Write header
00150     *ts << "<h2>" << (i18n("month_year","%1 %2").arg(TDEGlobal::locale()->calendar()->monthName(start))
00151         .arg(start.year())) << "</h2>\n";
00152     if ( TDEGlobal::locale()->weekStartDay() == 1 ) {
00153       start = start.addDays(1 - start.dayOfWeek());
00154     } else {
00155       if (start.dayOfWeek() != 7) {
00156         start = start.addDays(-start.dayOfWeek());
00157       }
00158     }
00159     *ts << "<table border=\"1\">\n";
00160 
00161     // Write table header
00162     *ts << "  <tr>";
00163     for(int i=0; i<7; ++i) {
00164       *ts << "<th>" << TDEGlobal::locale()->calendar()->weekDayName( start.addDays(i) ) << "</th>";
00165     }
00166     *ts << "</tr>\n";
00167 
00168     // Write days
00169     while (start <= end) {
00170       *ts << "  <tr>\n";
00171       for(int i=0;i<7;++i) {
00172         *ts << "    <td valign=\"top\"><table border=\"0\">";
00173 
00174         *ts << "<tr><td ";
00175         if (mHolidayMap.contains(start) || start.dayOfWeek() == 7) {
00176           *ts << "class=\"dateholiday\"";
00177         } else {
00178           *ts << "class=\"date\"";
00179         }
00180         *ts << ">" << TQString::number(start.day());
00181 
00182         if (mHolidayMap.contains(start)) {
00183           *ts << " <em>" << mHolidayMap[start] << "</em>";
00184         }
00185 
00186         *ts << "</td></tr><tr><td valign=\"top\">";
00187 
00188         // Only print events within the from-to range
00189         if ( start >= fromDate() && start <= toDate() ) {
00190           Event::List events = mCalendar->events( start,
00191                                                   EventSortStartDate,
00192                                                   SortDirectionAscending );
00193           if (events.count()) {
00194             *ts << "<table>";
00195             Event::List::ConstIterator it;
00196             for( it = events.begin(); it != events.end(); ++it ) {
00197             if ( checkSecrecy( *it ) ) {
00198               createEvent( ts, *it, start, false );
00199             }
00200             }
00201             *ts << "</table>";
00202           } else {
00203             *ts << "&nbsp;";
00204           }
00205         }
00206 
00207         *ts << "</td></tr></table></td>\n";
00208         start = start.addDays(1);
00209       }
00210       *ts << "  </tr>\n";
00211     }
00212     *ts << "</table>\n";
00213     startmonth += 1;
00214     if ( startmonth > 12 ) {
00215       startyear += 1;
00216       startmonth = 1;
00217     }
00218     start.setYMD( startyear, startmonth, 1 );
00219     end.setYMD(start.year(),start.month(),start.daysInMonth());
00220   }
00221 }
00222 
00223 void HtmlExport::createEventList (TQTextStream *ts)
00224 {
00225   int columns = 3;
00226   *ts << "<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
00227   *ts << "  <tr>\n";
00228   *ts << "    <th class=\"sum\">" << i18n("Start Time") << "</th>\n";
00229   *ts << "    <th>" << i18n("End Time") << "</th>\n";
00230   *ts << "    <th>" << i18n("Event") << "</th>\n";
00231   if ( mSettings->eventLocation() ) {
00232     *ts << "    <th>" << i18n("Location") << "</th>\n";
00233     ++columns;
00234   }
00235   if ( mSettings->eventCategories() ) {
00236     *ts << "    <th>" << i18n("Categories") << "</th>\n";
00237     ++columns;
00238   }
00239   if ( mSettings->eventAttendees() ) {
00240     *ts << "    <th>" << i18n("Attendees") << "</th>\n";
00241     ++columns;
00242   }
00243 
00244   *ts << "  </tr>\n";
00245 
00246   for ( TQDate dt = fromDate(); dt <= toDate(); dt = dt.addDays(1) ) {
00247     kdDebug(5850) << "Getting events for " << TQString(dt.toString()) << endl;
00248     Event::List events = mCalendar->events(dt,
00249                                            EventSortStartDate,
00250                                            SortDirectionAscending );
00251     if (events.count()) {
00252       Event::List::ConstIterator it;
00253       bool first = true;
00254       for( it = events.begin(); it != events.end(); ++it ) {
00255         if ( checkSecrecy( *it ) ) {
00256           if ( first ) {
00257             *ts << "  <tr><td colspan=\"" << TQString::number(columns)
00258             << "\" class=\"datehead\"><i>"
00259             << TDEGlobal::locale()->formatDate(dt)
00260             << "</i></td></tr>\n";
00261             first = false;
00262           }
00263           createEvent( ts, *it, dt );
00264         }
00265       }
00266     }
00267   }
00268 
00269   *ts << "</table>\n";
00270 }
00271 
00272 void HtmlExport::createEvent (TQTextStream *ts, Event *event,
00273                                        TQDate date,bool withDescription)
00274 {
00275   kdDebug(5850) << "HtmlExport::createEvent(): " << event->summary() << endl;
00276   *ts << "  <tr>\n";
00277 
00278   if (!event->doesFloat()) {
00279     if (event->isMultiDay() && (event->dtStart().date() != date)) {
00280       *ts << "    <td>&nbsp;</td>\n";
00281     } else {
00282       *ts << "    <td valign=\"top\">"
00283           << IncidenceFormatter::timeToString( event->dtStart(), true )
00284           << "</td>\n";
00285     }
00286     if (event->isMultiDay() && (event->dtEnd().date() != date)) {
00287       *ts << "    <td>&nbsp;</td>\n";
00288     } else {
00289       *ts << "    <td valign=\"top\">"
00290           << IncidenceFormatter::timeToString( event->dtEnd(), true )
00291           << "</td>\n";
00292     }
00293   } else {
00294     *ts << "    <td>&nbsp;</td><td>&nbsp;</td>\n";
00295   }
00296 
00297   *ts << "    <td class=\"sum\">\n";
00298   *ts << "      <b>" << cleanChars(event->summary()) << "</b>\n";
00299   if ( withDescription && !event->description().isEmpty() ) {
00300     *ts << "      <p>" << breakString( cleanChars( event->description() ) ) << "</p>\n";
00301   }
00302   *ts << "    </td>\n";
00303 
00304   if ( mSettings->eventLocation() ) {
00305     *ts << "  <td>\n";
00306     formatLocation( ts, event );
00307     *ts << "  </td>\n";
00308   }
00309 
00310   if ( mSettings->eventCategories() ) {
00311     *ts << "  <td>\n";
00312     formatCategories( ts, event );
00313     *ts << "  </td>\n";
00314   }
00315 
00316   if ( mSettings->eventAttendees() ) {
00317     *ts << "  <td>\n";
00318     formatAttendees( ts, event );
00319     *ts << "  </td>\n";
00320   }
00321 
00322   *ts << "  </tr>\n";
00323 }
00324 
00325 void HtmlExport::createTodoList ( TQTextStream *ts )
00326 {
00327   Todo::List rawTodoList = mCalendar->todos();
00328 
00329   Todo::List::Iterator it = rawTodoList.begin();
00330   while ( it != rawTodoList.end() ) {
00331     Todo *ev = *it;
00332     Todo *subev = ev;
00333     if ( ev->relatedTo() ) {
00334       if ( ev->relatedTo()->type()=="Todo" ) {
00335         if ( rawTodoList.find( static_cast<Todo *>( ev->relatedTo() ) ) ==
00336              rawTodoList.end() ) {
00337           rawTodoList.append( static_cast<Todo *>( ev->relatedTo() ) );
00338         }
00339       }
00340     }
00341     it = rawTodoList.find( subev );
00342     ++it;
00343   }
00344 
00345   // FIXME: Sort list by priorities. This is brute force and should be
00346   // replaced by a real sorting algorithm.
00347   Todo::List todoList;
00348   for ( int i = 1; i <= 9; ++i ) {
00349     for( it = rawTodoList.begin(); it != rawTodoList.end(); ++it ) {
00350       if ( (*it)->priority() == i && checkSecrecy( *it ) ) {
00351         todoList.append( *it );
00352       }
00353     }
00354   }
00355   for( it = rawTodoList.begin(); it != rawTodoList.end(); ++it ) {
00356     if ( (*it)->priority() == 0 && checkSecrecy( *it ) ) {
00357       todoList.append( *it );
00358     }
00359  }
00360 
00361   int columns = 3;
00362   *ts << "<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
00363   *ts << "  <tr>\n";
00364   *ts << "    <th class=\"sum\">" << i18n("Task") << "</th>\n";
00365   *ts << "    <th>" << i18n("Priority") << "</th>\n";
00366   *ts << "    <th>" << i18n("Completed") << "</th>\n";
00367   if ( mSettings->taskDueDate() ) {
00368     *ts << "    <th>" << i18n("Due Date") << "</th>\n";
00369     ++columns;
00370   }
00371   if ( mSettings->taskLocation() ) {
00372     *ts << "    <th>" << i18n("Location") << "</th>\n";
00373     ++columns;
00374   }
00375   if ( mSettings->taskCategories() ) {
00376     *ts << "    <th>" << i18n("Categories") << "</th>\n";
00377     ++columns;
00378   }
00379   if ( mSettings->taskAttendees() ) {
00380     *ts << "    <th>" << i18n("Attendees") << "</th>\n";
00381     ++columns;
00382   }
00383   *ts << "  </tr>\n";
00384 
00385   // Create top-level list.
00386   for( it = todoList.begin(); it != todoList.end(); ++it ) {
00387     if ( !(*it)->relatedTo() ) createTodo( ts, *it );
00388   }
00389 
00390   // Create sub-level lists
00391   for( it = todoList.begin(); it != todoList.end(); ++it ) {
00392     Incidence::List relations = (*it)->relations();
00393     if (relations.count()) {
00394       // Generate sub-task list of event ev
00395       *ts << "  <tr>\n";
00396       *ts << "    <td class=\"subhead\" colspan=";
00397       *ts << "\"" << TQString::number(columns) << "\"";
00398       *ts << "><a name=\"sub" << (*it)->uid() << "\"></a>"
00399           << i18n("Sub-Tasks of: ") << "<a href=\"#"
00400           << (*it)->uid() << "\"><b>" << cleanChars( (*it)->summary())
00401           << "</b></a></td>\n";
00402       *ts << "  </tr>\n";
00403 
00404       Todo::List sortedList;
00405       // FIXME: Sort list by priorities. This is brute force and should be
00406       // replaced by a real sorting algorithm.
00407       for ( int i = 1; i <= 9; ++i ) {
00408         Incidence::List::ConstIterator it2;
00409         for( it2 = relations.begin(); it2 != relations.end(); ++it2 ) {
00410           Todo *ev3 = dynamic_cast<Todo *>( *it2 );
00411           if ( ev3 && ev3->priority() == i ) sortedList.append( ev3 );
00412         }
00413       }
00414       Incidence::List::ConstIterator it2;
00415       for( it2 = relations.begin(); it2 != relations.end(); ++it2 ) {
00416         Todo *ev3 = dynamic_cast<Todo *>( *it2 );
00417         if ( ev3 && ev3->priority() == 0 ) sortedList.append( ev3 );
00418       }
00419 
00420       Todo::List::ConstIterator it3;
00421       for( it3 = sortedList.begin(); it3 != sortedList.end(); ++it3 ) {
00422         createTodo( ts, *it3 );
00423       }
00424     }
00425   }
00426 
00427   *ts << "</table>\n";
00428 }
00429 
00430 void HtmlExport::createTodo (TQTextStream *ts,Todo *todo)
00431 {
00432   kdDebug(5850) << "HtmlExport::createTodo()" << endl;
00433 
00434   bool completed = todo->isCompleted();
00435   Incidence::List relations = todo->relations();
00436 
00437   *ts << "<tr>\n";
00438 
00439   *ts << "  <td class=\"sum";
00440   if (completed) *ts << "done";
00441   *ts << "\">\n";
00442   *ts << "    <a name=\"" << todo->uid() << "\"></a>\n";
00443   *ts << "    <b>" << cleanChars(todo->summary()) << "</b>\n";
00444   if (!todo->description().isEmpty()) {
00445     *ts << "    <p>" << breakString(cleanChars(todo->description())) << "</p>\n";
00446   }
00447   if (relations.count()) {
00448     *ts << "    <div align=\"right\"><a href=\"#sub" << todo->uid()
00449         << "\">" << i18n("Sub-Tasks") << "</a></div>\n";
00450   }
00451   *ts << "  </td>\n";
00452 
00453   *ts << "  <td";
00454   if (completed) *ts << " class=\"done\"";
00455   *ts << ">\n";
00456   *ts << "    " << todo->priority() << "\n";
00457   *ts << "  </td>\n";
00458 
00459   *ts << "  <td";
00460   if (completed) *ts << " class=\"done\"";
00461   *ts << ">\n";
00462   *ts << "    " << i18n("%1 %").arg(todo->percentComplete()) << "\n";
00463   *ts << "  </td>\n";
00464 
00465   if ( mSettings->taskDueDate() ) {
00466     *ts << "  <td";
00467     if (completed) *ts << " class=\"done\"";
00468     *ts << ">\n";
00469     if (todo->hasDueDate()) {
00470       *ts << "    " << IncidenceFormatter::dateToString( todo->dtDue( true ) ) << "\n";
00471     } else {
00472       *ts << "    &nbsp;\n";
00473     }
00474     *ts << "  </td>\n";
00475   }
00476 
00477   if ( mSettings->taskLocation() ) {
00478     *ts << "  <td";
00479     if (completed) *ts << " class=\"done\"";
00480     *ts << ">\n";
00481     formatLocation(ts,todo);
00482     *ts << "  </td>\n";
00483   }
00484 
00485   if ( mSettings->taskCategories() ) {
00486     *ts << "  <td";
00487     if (completed) *ts << " class=\"done\"";
00488     *ts << ">\n";
00489     formatCategories(ts,todo);
00490     *ts << "  </td>\n";
00491   }
00492 
00493   if ( mSettings->taskAttendees() ) {
00494     *ts << "  <td";
00495     if (completed) *ts << " class=\"done\"";
00496     *ts << ">\n";
00497     formatAttendees(ts,todo);
00498     *ts << "  </td>\n";
00499   }
00500 
00501   *ts << "</tr>\n";
00502 }
00503 
00504 void HtmlExport::createWeekView( TQTextStream */*ts*/ )
00505 {
00506   // FIXME: Implement this!
00507 }
00508 
00509 void HtmlExport::createJournalView( TQTextStream */*ts*/ )
00510 {
00511 //   Journal::List rawJournalList = mCalendar->journals();
00512   // FIXME: Implement this!
00513 }
00514 
00515 void HtmlExport::createFreeBusyView( TQTextStream */*ts*/ )
00516 {
00517   // FIXME: Implement this!
00518 }
00519 
00520 bool HtmlExport::checkSecrecy( Incidence *incidence )
00521 {
00522   int secrecy = incidence->secrecy();
00523   if ( secrecy == Incidence::SecrecyPublic ) {
00524     return true;
00525   }
00526   if ( secrecy == Incidence::SecrecyPrivate && !mSettings->excludePrivate() ) {
00527     return true;
00528   }
00529   if ( secrecy == Incidence::SecrecyConfidential &&
00530        !mSettings->excludeConfidential() ) {
00531     return true;
00532   }
00533   return false;
00534 }
00535 
00536 void HtmlExport::formatLocation (TQTextStream *ts,Incidence *event)
00537 {
00538   if (!event->location().isEmpty()) {
00539     *ts << "    " << cleanChars(event->location()) << "\n";
00540   } else {
00541     *ts << "    &nbsp;\n";
00542   }
00543 }
00544 
00545 void HtmlExport::formatCategories (TQTextStream *ts,Incidence *event)
00546 {
00547   if (!event->categoriesStr().isEmpty()) {
00548     *ts << "    " << cleanChars(event->categoriesStr()) << "\n";
00549   } else {
00550     *ts << "    &nbsp;\n";
00551   }
00552 }
00553 
00554 void HtmlExport::formatAttendees( TQTextStream *ts, Incidence *event )
00555 {
00556   Attendee::List attendees = event->attendees();
00557   if (attendees.count()) {
00558     *ts << "<em>";
00559 #ifndef KORG_NOKABC
00560     TDEABC::AddressBook *add_book = TDEABC::StdAddressBook::self( true );
00561     TDEABC::Addressee::List addressList;
00562     addressList = add_book->findByEmail(event->organizer().email());
00563     TDEABC::Addressee o = addressList.first();
00564     if (!o.isEmpty() && addressList.size()<2) {
00565       *ts << "<a href=\"mailto:" << event->organizer().email() << "\">";
00566       *ts << cleanChars(o.formattedName()) << "</a>\n";
00567     }
00568     else *ts << event->organizer().fullName();
00569 #else
00570     *ts << event->organizer().fullName();
00571 #endif
00572     *ts << "</em><br />";
00573     Attendee::List::ConstIterator it;
00574     for( it = attendees.begin(); it != attendees.end(); ++it ) {
00575       Attendee *a = *it;
00576       if (!a->email().isEmpty()) {
00577         *ts << "<a href=\"mailto:" << a->email();
00578         *ts << "\">" << cleanChars(a->name()) << "</a>";
00579       }
00580       else {
00581         *ts << "    " << cleanChars(a->name());
00582       }
00583       *ts << "<br />" << "\n";
00584     }
00585   } else {
00586     *ts << "    &nbsp;\n";
00587   }
00588 }
00589 
00590 TQString HtmlExport::breakString(const TQString &text)
00591 {
00592   int number = text.contains("\n");
00593   if(number < 0) {
00594     return text;
00595   } else {
00596     TQString out;
00597     TQString tmpText = text;
00598     int pos = 0;
00599     TQString tmp;
00600     for(int i=0;i<=number;i++) {
00601       pos = tmpText.find("\n");
00602       tmp = tmpText.left(pos);
00603       tmpText = tmpText.right(tmpText.length() - pos - 1);
00604       out += tmp + "<br />";
00605     }
00606     return out;
00607   }
00608 }
00609 
00610 void HtmlExport::createFooter( TQTextStream *ts )
00611 {
00612   // FIXME: Implement this in a translatable way!
00613   TQString trailer = i18n("This page was created ");
00614 
00615 /*  bool hasPerson = false;
00616   bool hasCredit = false;
00617   bool hasCreditURL = false;
00618   TQString mail, name, credit, creditURL;*/
00619   if (!mSettings->eMail().isEmpty()) {
00620     if (!mSettings->name().isEmpty())
00621       trailer += i18n("by <a href=\"mailto:%1\">%2</a> ").arg( mSettings->eMail() ).arg( mSettings->name() );
00622     else
00623       trailer += i18n("by <a href=\"mailto:%1\">%2</a> ").arg( mSettings->eMail() ).arg( mSettings->eMail() );
00624   } else {
00625     if (!mSettings->name().isEmpty())
00626       trailer += i18n("by %1 ").arg( mSettings->name() );
00627   }
00628   if (!mSettings->creditName().isEmpty()) {
00629     if (!mSettings->creditURL().isEmpty())
00630       trailer += i18n("with <a href=\"%1\">%2</a>")
00631                      .arg( mSettings->creditURL() )
00632                      .arg( mSettings->creditName() );
00633     else
00634       trailer += i18n("with %1").arg( mSettings->creditName() );
00635   }
00636   *ts << "<p>" << trailer << "</p>\n";
00637 }
00638 
00639 
00640 TQString HtmlExport::cleanChars(const TQString &text)
00641 {
00642   TQString txt = text;
00643   txt = txt.replace( "&", "&amp;" );
00644   txt = txt.replace( "<", "&lt;" );
00645   txt = txt.replace( ">", "&gt;" );
00646   txt = txt.replace( "\"", "&quot;" );
00647   txt = txt.replace( TQString::fromUtf8("ä"), "&auml;" );
00648   txt = txt.replace( TQString::fromUtf8("á"), "&aacute;" );
00649   txt = txt.replace( TQString::fromUtf8("à"), "&agrave;" );
00650   txt = txt.replace( TQString::fromUtf8("â"), "&acirc;" );
00651   txt = txt.replace( TQString::fromUtf8("Ä"), "&Auml;" );
00652   txt = txt.replace( TQString::fromUtf8("ó"), "&oacute;" );
00653   txt = txt.replace( TQString::fromUtf8("ô"), "&ocirc;" );
00654   txt = txt.replace( TQString::fromUtf8("ö"), "&ouml;" );
00655   txt = txt.replace( TQString::fromUtf8("Ö"), "&Ouml;" );
00656   txt = txt.replace( TQString::fromUtf8("ü"), "&uuml;" );
00657   txt = txt.replace( TQString::fromUtf8("Ü"), "&Uuml;" );
00658   txt = txt.replace( TQString::fromUtf8("ß"), "&szlig;" );
00659   txt = txt.replace( TQString::fromUtf8("€"), "&euro;" );
00660   txt = txt.replace( TQString::fromUtf8("é"), "&eacute;" );
00661   txt = txt.replace( TQString::fromUtf8("ë"), "&euml;" );
00662   txt = txt.replace( TQString::fromUtf8("è"), "&egrave;" );
00663   txt = txt.replace( TQString::fromUtf8("ñ"), "&ntilde;" );
00664   txt = txt.replace( TQString::fromUtf8("ç"), "&ccedil;" );
00665 
00666   return txt;
00667 }
00668 
00669 TQString HtmlExport::styleSheet() const
00670 {
00671   if ( !mSettings->styleSheet().isEmpty() )
00672     return mSettings->styleSheet();
00673 
00674   TQString css;
00675 
00676   if ( TQApplication::reverseLayout() ) {
00677     css += "    body { background-color:white; color:black; direction: rtl }\n";
00678     css += "    td { text-align:center; background-color:#eee }\n";
00679     css += "    th { text-align:center; background-color:#228; color:white }\n";
00680     css += "    td.sumdone { background-color:#ccc }\n";
00681     css += "    td.done { background-color:#ccc }\n";
00682     css += "    td.subhead { text-align:center; background-color:#ccf }\n";
00683     css += "    td.datehead { text-align:center; background-color:#ccf }\n";
00684     css += "    td.space { background-color:white }\n";
00685     css += "    td.dateholiday { color:red }\n";
00686   } else {
00687     css += "    body { background-color:white; color:black }\n";
00688     css += "    td { text-align:center; background-color:#eee }\n";
00689     css += "    th { text-align:center; background-color:#228; color:white }\n";
00690     css += "    td.sum { text-align:left }\n";
00691     css += "    td.sumdone { text-align:left; background-color:#ccc }\n";
00692     css += "    td.done { background-color:#ccc }\n";
00693     css += "    td.subhead { text-align:center; background-color:#ccf }\n";
00694     css += "    td.datehead { text-align:center; background-color:#ccf }\n";
00695     css += "    td.space { background-color:white }\n";
00696     css += "    td.date { text-align:left }\n";
00697     css += "    td.dateholiday { text-align:left; color:red }\n";
00698   }
00699 
00700   return css;
00701 }
00702 
00703 
00704 void HtmlExport::addHoliday( const TQDate &date, const TQString &name)
00705 {
00706   if ( mHolidayMap[date].isEmpty() ) {
00707     mHolidayMap[date] = name;
00708   } else {
00709     mHolidayMap[date] = i18n("list of holidays", "%1, %2").arg(mHolidayMap[date]).arg(name);
00710   }
00711 }
00712 
00713 TQDate HtmlExport::fromDate() const
00714 {
00715   return mSettings->dateStart().date();
00716 }
00717 
00718 TQDate HtmlExport::toDate() const
00719 {
00720   return mSettings->dateEnd().date();
00721 }