libkcal Library API Documentation

htmlexport.cpp

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