korganizer Library API Documentation

htmlexport.cpp

00001 /*
00002     This file is part of KOrganizer.
00003     Copyright (c) 2000, 2001 Cornelius Schumacher <schumacher@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019     As a special exception, permission is given to link this program
00020     with any edition of Qt, and distribute the resulting executable,
00021     without including the source code for Qt in the source distribution.
00022 */
00023 
00024 #include <qapplication.h>
00025 #include <qfile.h>
00026 #include <qtextstream.h>
00027 #include <qtextcodec.h>
00028 #include <qregexp.h> 
00029 
00030 #include <kglobal.h>
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033 
00034 #include <libkcal/calendar.h>
00035 #include <libkcal/event.h>
00036 #include <libkcal/todo.h>
00037 
00038 #include "kocore.h"
00039 #include "koprefs.h"
00040 #ifndef KORG_NOKABC
00041  #include <kabc/stdaddressbook.h>
00042 #endif
00043 #include "htmlexport.h"
00044 
00045 bool HtmlExport::save(const QString &fileName)
00046 {
00047   QFile f(fileName);
00048   if (!f.open(IO_WriteOnly)) {
00049     return false;
00050   }
00051   QTextStream ts(&f);
00052   bool success = save(&ts);
00053   f.close();
00054   return success;
00055 }
00056 
00057 bool HtmlExport::save(QTextStream *ts)
00058 {
00059   ts->setEncoding(QTextStream::UnicodeUTF8);
00060 
00061   // Write HTML header
00062   *ts << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ";
00063   *ts << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
00064 
00065   *ts << "<html><head>" << endl;
00066   *ts << "  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=";
00067   *ts << "UTF-8\" />\n";
00068   *ts << "  <title>" << i18n("KOrganizer To-Do List") << "</title>\n";
00069   *ts << "  <style type=\"text/css\">\n";
00070   *ts << styleSheet();
00071   *ts << "  </style>\n";
00072   *ts << "</head><body>\n";
00073 
00074   // TO DO: Write KOrganizer header
00075   // (Heading, Calendar-Owner, Calendar-Date, ...)
00076 
00077   if (eventsEnabled() || monthViewEnabled()) {
00078     *ts << "<h1>" << i18n("KOrganizer Calendar") << "</h1>\n";
00079   }
00080 
00081   // Write Month View
00082   if (monthViewEnabled()) {
00083     createHtmlMonthView(ts);
00084   }
00085 
00086   // Write Event List
00087   if (eventsEnabled()) {
00088     // Write HTML page content
00089     createHtmlEventList(ts);
00090   }
00091 
00092   // Write Todo List
00093   if (todosEnabled()) {
00094     *ts << "<h1>" << i18n("KOrganizer To-Do List") << "</h1>\n";
00095 
00096     // Write HTML page content
00097     createHtmlTodoList(ts);
00098   }
00099 
00100   // Write KOrganizer trailer
00101   *ts << "<p>" << i18n("This page was created by ");
00102         *ts << "<a href=\"mailto:" << KOPrefs::instance()->email() << "\">";
00103         *ts << KOPrefs::instance()->fullName() << "</a>";
00104         *ts << i18n(" with <a href=\"http://korganizer.kde.org\">KOrganizer</a>");
00105         *ts << "</p>\n";
00106 
00107   // Write HTML trailer
00108   *ts << "</body></html>\n";
00109 
00110   return true;
00111 }
00112 
00113 void HtmlExport::createHtmlMonthView(QTextStream *ts)
00114 {
00115   QDate start = fromDate();
00116   start.setYMD(start.year(),start.month(),1);  // go back to first day in month
00117 
00118   QDate end(start.year(),start.month(),start.daysInMonth());
00119 
00120   int startmonth = start.month();
00121   int startyear = start.year();
00122 
00123   while ( start < toDate() ) {
00124     // Write header
00125     *ts << "<h2>" << (i18n("month_year","%1 %2").arg(KGlobal::locale()->monthName(start.month()))
00126         .arg(start.year())) << "</h2>\n";
00127     if (KGlobal::locale()->weekStartsMonday()) {
00128       start = start.addDays(1 - start.dayOfWeek());
00129     } else {
00130       if (start.dayOfWeek() != 7) {
00131         start = start.addDays(-start.dayOfWeek());
00132       }
00133     }
00134     *ts << "<table border=\"1\">\n";
00135 
00136     // Write table header
00137     *ts << "  <tr>";
00138     for(int i=0; i<7; ++i) {
00139       *ts << "<th>" << KGlobal::locale()->weekDayName(start.addDays(i).dayOfWeek()) << "</th>";
00140     }
00141     *ts << "</tr>\n";
00142 
00143     // Write days
00144     while (start <= end) {
00145       *ts << "  <tr>\n";
00146       for(int i=0;i<7;++i) {
00147         *ts << "    <td valign=\"top\"><table border=\"0\">";
00148 
00149         QString holiday = KOCore::self()->holiday(start);
00150 
00151         *ts << "<tr><td ";
00152         if (!holiday.isEmpty() || start.dayOfWeek() == 7) {
00153           *ts << "class=\"dateholiday\"";
00154         } else {
00155           *ts << "class=\"date\"";
00156         }
00157         *ts << ">" << QString::number(start.day());
00158 
00159         if (!holiday.isEmpty()) {
00160           *ts << " <em>" << holiday << "</em>";
00161         }
00162 
00163         *ts << "</td></tr><tr><td valign=\"top\">";
00164 
00165         QPtrList<Event> events = mCalendar->events(start,true);
00166         if (events.count()) {
00167           *ts << "<table>";
00168           Event *ev;
00169           for(ev = events.first(); ev; ev = events.next()) {
00170             if ( checkSecrecy( ev ) ) {
00171               createHtmlEvent(ts,ev,start,false);
00172             }
00173           }
00174           *ts << "</table>";
00175         } else {
00176           *ts << "&nbsp;";
00177         }
00178 
00179         *ts << "</td></tr></table></td>\n";
00180         start = start.addDays(1);
00181       }
00182       *ts << "  </tr>\n";
00183     }
00184     *ts << "</table>\n";
00185     startmonth += 1;
00186     if ( startmonth > 12 ) {
00187       startyear += 1;
00188       startmonth = 1;
00189     }
00190     start.setYMD( startyear, startmonth, 1 );
00191     end.setYMD(start.year(),start.month(),start.daysInMonth());
00192   }
00193 }
00194 
00195 void HtmlExport::createHtmlEventList (QTextStream *ts)
00196 {
00197   *ts << "<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
00198   *ts << "  <tr>\n";
00199   *ts << "    <th class=\"sum\">" << i18n("Start Time") << "</th>\n";
00200   *ts << "    <th>" << i18n("End Time") << "</th>\n";
00201   *ts << "    <th>" << i18n("Event") << "</th>\n";
00202   if (categoriesEventEnabled()) {
00203     *ts << "    <th>" << i18n("Categories") << "</th>\n";
00204   }
00205   if (attendeesEventEnabled()) {
00206     *ts << "    <th>" << i18n("Attendees") << "</th>\n";
00207   }
00208 
00209   *ts << "  </tr>\n";
00210 
00211   int columns = 3;
00212   if (categoriesEventEnabled()) ++columns;
00213   if (attendeesEventEnabled()) ++columns;
00214 
00215   for (QDate dt = fromDate(); dt <= toDate(); dt = dt.addDays(1)) {
00216     kdDebug() << "Getting events for " << dt.toString() << endl;
00217     QPtrList<Event> events = mCalendar->events(dt,true);
00218     if (events.count()) {
00219       *ts << "  <tr><td colspan=\"" << QString::number(columns)
00220           << "\" class=\"datehead\"><i>"
00221           << KGlobal::locale()->formatDate(dt)
00222           << "</i></td></tr>\n";
00223       Event *ev;
00224       for(ev = events.first(); ev; ev = events.next()) {
00225         if ( checkSecrecy( ev ) ) {
00226           createHtmlEvent(ts,ev,dt);
00227         }
00228       }
00229     }
00230   }
00231 
00232   *ts << "</table>\n";
00233 }
00234 
00235 void HtmlExport::createHtmlEvent (QTextStream *ts, Event *event,
00236                                        QDate date,bool withDescription)
00237 {
00238   kdDebug() << "HtmlExport::createHtmlEvent(): " << event->summary() << endl;
00239   *ts << "  <tr>\n";
00240 
00241   if (!event->doesFloat()) {
00242     if (event->isMultiDay() && (event->dtStart().date() != date)) {
00243       *ts << "    <td>&nbsp;</td>\n";
00244     } else {
00245       *ts << "    <td valign=\"top\">" << event->dtStartTimeStr() << "</td>\n";
00246     }
00247     if (event->isMultiDay() && (event->dtEnd().date() != date)) {
00248       *ts << "    <td>&nbsp;</td>\n";
00249     } else {
00250       *ts << "    <td valign=\"top\">" << event->dtEndTimeStr() << "</td>\n";
00251     }
00252   } else {
00253     *ts << "    <td>&nbsp;</td><td>&nbsp;</td>\n";
00254   }
00255 
00256   *ts << "    <td class=\"sum\">\n";
00257   *ts << "      <b>" << cleanChars(event->summary()) << "</b>\n";
00258   if (withDescription && !event->description().isEmpty()) {
00259     *ts << "      <p>" << breakString(cleanChars(event->description())) << "</p>\n";
00260   }
00261   *ts << "    </td>\n";
00262 
00263   if (categoriesEventEnabled()) {
00264     *ts << "  <td>\n";
00265     formatHtmlCategories(ts,event);
00266     *ts << "  </td>\n";
00267   }
00268 
00269   if (attendeesEventEnabled()) {
00270     *ts << "  <td>\n";
00271     formatHtmlAttendees(ts,event);
00272     *ts << "  </td>\n";
00273   }
00274 
00275   *ts << "  </tr>\n";
00276 }
00277 
00278 void HtmlExport::createHtmlTodoList (QTextStream *ts)
00279 {
00280   Todo *ev,*subev;
00281 
00282   QPtrList<Todo> rawTodoList = mCalendar->todos();
00283   QPtrList<Todo> todoList;
00284 
00285   ev = rawTodoList.first();
00286   while (ev) {
00287     subev = ev;
00288     if (ev->relatedTo()) {
00289       if (ev->relatedTo()->type()=="Todo") {
00290         if (rawTodoList.find(static_cast<Todo*>(ev->relatedTo()))<0) {
00291           rawTodoList.append(static_cast<Todo*>(ev->relatedTo()));
00292         }
00293       }
00294     }
00295     rawTodoList.find(subev);
00296     ev = rawTodoList.next();
00297   }
00298 
00299   // Sort list by priorities. This is brute force and should be
00300   // replaced by a real sorting algorithm.
00301   for (int i=1; i<=5; ++i) {
00302     for(ev=rawTodoList.first();ev;ev=rawTodoList.next()) {
00303       if (ev->priority()==i && checkSecrecy( ev )) todoList.append(ev);
00304     }
00305   }
00306 
00307   *ts << "<table border=\"0\" cellpadding=\"3\" cellspacing=\"3\">\n";
00308   *ts << "  <tr>\n";
00309   *ts << "    <th class=\"sum\">" << i18n("Task") << "</th>\n";
00310   *ts << "    <th>" << i18n("Priority") << "</th>\n";
00311   *ts << "    <th>" << i18n("Completed") << "</th>\n";
00312   if (dueDateEnabled()) {
00313     *ts << "    <th>" << i18n("Due Date") << "</th>\n";
00314   }
00315   if (categoriesTodoEnabled()) {
00316     *ts << "    <th>" << i18n("Categories") << "</th>\n";
00317   }
00318   if (attendeesTodoEnabled()) {
00319     *ts << "    <th>" << i18n("Attendees") << "</th>\n";
00320   }
00321   *ts << "  </tr>\n";
00322 
00323   // Create top-level list.
00324   for(ev=todoList.first();ev;ev=todoList.next()) {
00325     if (!ev->relatedTo()) createHtmlTodo(ts,ev);
00326   }
00327 
00328   // Create sub-level lists
00329   for(ev=todoList.first();ev;ev=todoList.next()) {
00330     QPtrList<Incidence> relations = ev->relations();
00331     if (relations.count()) {
00332       // Generate sub-task list of event ev
00333       *ts << "  <tr>\n";
00334       *ts << "    <td class=\"subhead\" colspan=";
00335       int columns = 3;
00336       if (dueDateEnabled()) ++columns;
00337       if (categoriesTodoEnabled()) ++columns;
00338       if (attendeesTodoEnabled()) ++columns;
00339       *ts << "\"" << QString::number(columns) << "\"";
00340       *ts << "><a name=\"sub" << ev->uid() << "\"></a>"
00341           << i18n("Sub-Tasks of: ") << "<a href=\"#"
00342           << ev->uid() << "\"><b>" << cleanChars(ev->summary()) << "</b></a></td>\n";
00343       *ts << "  </tr>\n";
00344 
00345       QPtrList<Todo> sortedList;
00346       Incidence *ev2;
00347       // Sort list by priorities. This is brute force and should be
00348       // replaced by a real sorting algorithm.
00349       for (int i=1; i<=5; ++i) {
00350         for(ev2=relations.first();ev2;ev2=relations.next()) {
00351           Todo *ev3 = dynamic_cast<Todo *>(ev2);
00352           if (ev3 && ev3->priority() == i) sortedList.append(ev3);
00353         }
00354       }
00355 
00356       for(subev=sortedList.first();subev;subev=sortedList.next()) {
00357         createHtmlTodo(ts,subev);
00358       }
00359     }
00360   }
00361 
00362   *ts << "</table>\n";
00363 }
00364 
00365 void HtmlExport::createHtmlTodo (QTextStream *ts,Todo *todo)
00366 {
00367   kdDebug() << "HtmlExport::createHtmlTodo()" << endl;
00368 
00369   bool completed = todo->isCompleted();
00370   QPtrList<Incidence> relations = todo->relations();
00371 
00372   *ts << "<tr>\n";
00373 
00374   *ts << "  <td class=\"sum\"";
00375   if (completed) *ts << "done";
00376   *ts << ">\n";
00377   *ts << "    <a name=\"" << todo->uid() << "\"></a>\n";
00378   *ts << "    <b>" << cleanChars(todo->summary()) << "</b>\n";
00379   if (!todo->description().isEmpty()) {
00380     *ts << "    <p>" << breakString(cleanChars(todo->description())) << "</p>\n";
00381   }
00382   if (relations.count()) {
00383     *ts << "    <div align=\"right\"><a href=\"#sub" << todo->uid()
00384         << "\">" << i18n("Sub-Tasks") << "</a></div>\n";
00385   }
00386 
00387   *ts << "  </td";
00388   if (completed) *ts << " class=\"done\"";
00389   *ts << ">\n";
00390 
00391   *ts << "  <td";
00392   if (completed) *ts << " class=\"done\"";
00393   *ts << ">\n";
00394   *ts << "    " << todo->priority() << "\n";
00395   *ts << "  </td>\n";
00396 
00397   *ts << "  <td";
00398   if (completed) *ts << " class=\"done\"";
00399   *ts << ">\n";
00400   *ts << "    " << i18n("%1 %").arg(todo->percentComplete()) << "\n";
00401   *ts << "  </td>\n";
00402 
00403   if (dueDateEnabled()) {
00404     *ts << "  <td";
00405     if (completed) *ts << " class=\"done\"";
00406     *ts << ">\n";
00407     if (todo->hasDueDate()) {
00408       *ts << "    " << todo->dtDueDateStr() << "\n";
00409     } else {
00410       *ts << "    &nbsp;\n";
00411     }
00412     *ts << "  </td>\n";
00413   }
00414 
00415   if (categoriesTodoEnabled()) {
00416     *ts << "  <td";
00417     if (completed) *ts << " class=\"done\"";
00418     *ts << ">\n";
00419     formatHtmlCategories(ts,todo);  
00420     *ts << "  </td>\n";  
00421   }
00422 
00423   if (attendeesTodoEnabled()) {
00424     *ts << "  <td";
00425     if (completed) *ts << " class=\"done\"";
00426     *ts << ">\n";
00427     formatHtmlAttendees(ts,todo);
00428     *ts << "  </td>\n";
00429   }
00430 
00431   *ts << "</tr>\n";
00432 }
00433 
00434 bool HtmlExport::checkSecrecy( Incidence *incidence )
00435 {
00436   int secrecy = incidence->secrecy();
00437   if ( secrecy == Incidence::SecrecyPublic ) {
00438     return true;
00439   }
00440   if ( secrecy == Incidence::SecrecyPrivate && !excludePrivateEventEnabled() ) {
00441     return true;
00442   }
00443   if ( secrecy == Incidence::SecrecyConfidential &&
00444        !excludeConfidentialEventEnabled() ) {
00445     return true;
00446   }
00447   return false;
00448 }
00449 
00450 void HtmlExport::formatHtmlCategories (QTextStream *ts,Incidence *event)
00451 {
00452   if (!event->categoriesStr().isEmpty()) {
00453     *ts << "    " << cleanChars(event->categoriesStr()) << "\n";
00454   } else {
00455     *ts << "    &nbsp;\n";
00456   }
00457 }
00458 
00459 void HtmlExport::formatHtmlAttendees (QTextStream *ts,Incidence *event)
00460 {
00461   QPtrList<Attendee> attendees = event->attendees();
00462   if (attendees.count()) {
00463           *ts << "<em>";
00464 #ifndef KORG_NOKABC
00465     KABC::AddressBook *add_book = KABC::StdAddressBook::self();
00466     KABC::Addressee::List addressList;
00467     addressList = add_book->findByEmail(event->organizer());
00468     KABC::Addressee o = addressList.first();
00469     if (!o.isEmpty() && addressList.size()<2) {
00470       *ts << "<a href=\"mailto:" << event->organizer() << "\">";
00471       *ts << cleanChars(o.formattedName()) << "</a>\n";
00472     }
00473                 else *ts << event->organizer();
00474 #else
00475           *ts << event->organizer();
00476 #endif
00477     *ts << "</em><br />";
00478     Attendee *a;
00479     for(a=attendees.first();a;a=attendees.next()) {
00480       if (!a->email().isEmpty()) {
00481                                 *ts << "<a href=\"mailto:" << a->email();
00482                                 *ts << "\">" << cleanChars(a->name()) << "</a>";
00483                   }
00484       else {
00485                           *ts << "    " << cleanChars(a->name());
00486                   }
00487       *ts << "<br />" << "\n";
00488     }
00489   } else {
00490     *ts << "    &nbsp;\n";
00491   }
00492 }
00493 
00494 QString HtmlExport::breakString(const QString &text)
00495 {
00496   int number = text.contains("\n");
00497   if(number < 0) {
00498     return text;
00499   } else {
00500     QString out;
00501     QString tmpText = text;
00502     int pos = 0;
00503     QString tmp;
00504     for(int i=0;i<=number;i++) {
00505       pos = tmpText.find("\n");
00506       tmp = tmpText.left(pos);
00507       tmpText = tmpText.right(tmpText.length() - pos - 1);
00508       out += tmp + "<br />";
00509     }
00510     return out;
00511   }
00512 }
00513 
00514 QString HtmlExport::cleanChars(const QString &text)
00515 {
00516   QString txt = text;
00517   txt = txt.replace( QRegExp("&"), "&amp;" );
00518   txt = txt.replace( QRegExp("<"), "&lt;" );
00519   txt = txt.replace( QRegExp(">"), "&gt;" );
00520   txt = txt.replace( QRegExp("\""), "&quot;" );
00521   txt = txt.replace( QRegExp("ä"), "&auml;" );
00522   txt = txt.replace( QRegExp("Ä"), "&Auml;" );
00523   txt = txt.replace( QRegExp("ö"), "&ouml;" );
00524   txt = txt.replace( QRegExp("Ö"), "&Ouml;" );
00525   txt = txt.replace( QRegExp("ü"), "&uuml;" );
00526   txt = txt.replace( QRegExp("Ü"), "&Uuml;" );
00527   txt = txt.replace( QRegExp("ß"), "&szlig;" );
00528   txt = txt.replace( QRegExp("¤"), "&euro;" );
00529   txt = txt.replace( QRegExp("é"), "&eacute;" );
00530 
00531   return txt;
00532 }
00533 
00534 void HtmlExport::setStyleSheet( const QString &styleSheet )
00535 {
00536   mStyleSheet = styleSheet;
00537 }
00538 
00539 QString HtmlExport::styleSheet()
00540 {
00541   if ( !mStyleSheet.isEmpty() ) return mStyleSheet;
00542 
00543   QString css;
00544 
00545   if ( QApplication::reverseLayout() ) {
00546     css += "    body { background-color:white; color:black; direction: rtl }\n";
00547     css += "    td { text-align:center; background-color:#eee }\n";
00548     css += "    th { text-align:center; background-color:#228; color:white }\n";
00549     css += "    td.sumdone { background-color:#ccc }\n";
00550     css += "    td.done { background-color:#ccc }\n";
00551     css += "    td.subhead { text-align:center; background-color:#ccf }\n";
00552     css += "    td.datehead { text-align:center; background-color:#ccf }\n";
00553     css += "    td.space { background-color:white }\n";
00554     css += "    td.dateholiday { color:red }\n";
00555   } else {
00556     css += "    body { background-color:white; color:black }\n";
00557     css += "    td { text-align:center; background-color:#eee }\n";
00558     css += "    th { text-align:center; background-color:#228; color:white }\n";
00559     css += "    td.sum { text-align:left }\n";
00560     css += "    td.sumdone { text-align:left; background-color:#ccc }\n";
00561     css += "    td.done { background-color:#ccc }\n";
00562     css += "    td.subhead { text-align:center; background-color:#ccf }\n";
00563     css += "    td.datehead { text-align:center; background-color:#ccf }\n";
00564     css += "    td.space { background-color:white }\n";
00565     css += "    td.date { text-align:left }\n";
00566     css += "    td.dateholiday { text-align:left; color:red }\n";
00567   }
00568   
00569   return css;
00570 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sat Oct 18 02:47:30 2003 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001