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 << " "; 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> </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> </td>\n"; 00288 } else { 00289 *ts << " <td valign=\"top\">" 00290 << IncidenceFormatter::timeToString( event->dtEnd(), true ) 00291 << "</td>\n"; 00292 } 00293 } else { 00294 *ts << " <td> </td><td> </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 << " \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 << " \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 << " \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 << " \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( "&", "&" ); 00644 txt = txt.replace( "<", "<" ); 00645 txt = txt.replace( ">", ">" ); 00646 txt = txt.replace( "\"", """ ); 00647 txt = txt.replace( TQString::fromUtf8("ä"), "ä" ); 00648 txt = txt.replace( TQString::fromUtf8("á"), "á" ); 00649 txt = txt.replace( TQString::fromUtf8("à"), "à" ); 00650 txt = txt.replace( TQString::fromUtf8("â"), "â" ); 00651 txt = txt.replace( TQString::fromUtf8("Ä"), "Ä" ); 00652 txt = txt.replace( TQString::fromUtf8("ó"), "ó" ); 00653 txt = txt.replace( TQString::fromUtf8("ô"), "ô" ); 00654 txt = txt.replace( TQString::fromUtf8("ö"), "ö" ); 00655 txt = txt.replace( TQString::fromUtf8("Ö"), "Ö" ); 00656 txt = txt.replace( TQString::fromUtf8("ü"), "ü" ); 00657 txt = txt.replace( TQString::fromUtf8("Ü"), "Ü" ); 00658 txt = txt.replace( TQString::fromUtf8("ß"), "ß" ); 00659 txt = txt.replace( TQString::fromUtf8("€"), "€" ); 00660 txt = txt.replace( TQString::fromUtf8("é"), "é" ); 00661 txt = txt.replace( TQString::fromUtf8("ë"), "ë" ); 00662 txt = txt.replace( TQString::fromUtf8("è"), "è" ); 00663 txt = txt.replace( TQString::fromUtf8("ñ"), "ñ" ); 00664 txt = txt.replace( TQString::fromUtf8("ç"), "ç" ); 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 }