• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

ktimetracker

task.cpp

Go to the documentation of this file.
00001 /*
00002  *     Copyright (C) 1997 by Stephan Kulow <coolo@kde.org>
00003  *                   2007 the ktimetracker developers
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 along
00016  *   with this program; if not, write to the
00017  *      Free Software Foundation, Inc.
00018  *      51 Franklin Street, Fifth Floor
00019  *      Boston, MA  02110-1301  USA.
00020  *
00021  */
00022 
00023 #include "task.h"
00024 
00025 #include <QDateTime>
00026 #include <QString>
00027 #include <QTimer>
00028 #include <QPixmap>
00029 
00030 #include <KDebug>
00031 #include <KIconLoader>
00032 
00033 #include <kcal/event.h>
00034 
00035 #include "karmutility.h"
00036 #include "ktimetracker.h"
00037 #include "preferences.h"
00038 
00039 QVector<QPixmap*> *Task::icons = 0;
00040 
00041 Task::Task( const QString& taskName, long minutes, long sessionTime,
00042             DesktopList desktops, TaskView *parent, bool konsolemode )
00043   : QObject(), QTreeWidgetItem(parent)
00044 { 
00045   init( taskName, minutes, sessionTime, 0, desktops, 0, 0, konsolemode );
00046 }
00047 
00048 Task::Task( const QString& taskName, long minutes, long sessionTime,
00049             DesktopList desktops, Task *parent)
00050   : QObject(), QTreeWidgetItem(parent) 
00051 {
00052   init( taskName, minutes, sessionTime, 0, desktops, 0, 0 );
00053 }
00054 
00055 Task::Task( KCal::Todo* todo, TaskView* parent, bool konsolemode )
00056   : QObject(), QTreeWidgetItem( parent )
00057 {
00058   long minutes = 0;
00059   QString name;
00060   long sessionTime = 0;
00061   QString sessionStartTiMe;
00062   int percent_complete = 0;
00063   int priority = 0;
00064   DesktopList desktops;
00065 
00066   parseIncidence( todo, minutes, sessionTime, sessionStartTiMe, name, desktops, percent_complete,
00067                   priority );
00068   init( name, minutes, sessionTime, sessionStartTiMe, desktops, percent_complete, priority, konsolemode );
00069 }
00070 
00071 int Task::depth()
00072 // Deliver the depth of a task, i.e. how many tasks are supertasks to it. 
00073 // A toplevel task has the depth 0.
00074 {
00075   kDebug(5970) << "Entering function";
00076   int res=0;
00077   Task* t=this;
00078   while ( ( t = t->parent() ) ) res++;
00079   kDebug(5970) << "Leaving function. depth is:" << res;
00080   return res;
00081 }
00082 
00083 void Task::init( const QString& taskName, long minutes, long sessionTime, QString sessionStartTiMe,
00084                  DesktopList desktops, int percent_complete, int priority, bool konsolemode )
00085 {
00086   // If our parent is the taskview then connect our totalTimesChanged
00087   // signal to its receiver
00088   if ( ! parent() )
00089     connect( this, SIGNAL( totalTimesChanged ( long, long ) ),
00090              treeWidget(), SLOT( taskTotalTimesChanged( long, long) ));
00091 
00092   connect( this, SIGNAL( deletingTask( Task* ) ),
00093            treeWidget(), SLOT( deletingTask( Task* ) ));
00094 
00095   if (icons == 0) 
00096   {
00097     icons = new QVector<QPixmap*>(8);
00098     if (!konsolemode) 
00099     {
00100       KIconLoader kil("ktimetracker"); // always load icons from the KArm application
00101       for (int i=0; i<8; i++)
00102       {
00103         QPixmap *icon = new QPixmap();
00104         QString name;
00105         name.sprintf("watch-%d.xpm",i);
00106         *icon = kil.loadIcon( name, KIconLoader::User );
00107         icons->insert(i,icon);
00108       } 
00109     }
00110   }
00111 
00112   mRemoving = false;
00113   mName = taskName.trimmed();
00114   mLastStart = QDateTime::currentDateTime();
00115   mTotalTime = mTime = minutes;
00116   mTotalSessionTime = mSessionTime = sessionTime;
00117   mTimer = new QTimer(this);
00118   mDesktops = desktops;
00119   connect(mTimer, SIGNAL(timeout()), this, SLOT(updateActiveIcon()));
00120   if ( !konsolemode ) setIcon(1, UserIcon(QString::fromLatin1("empty-watch.xpm")));
00121   mCurrentPic = 0;
00122   mPercentComplete = percent_complete;
00123   mPriority = priority;
00124   mSessionStartTiMe=KDateTime::fromString(sessionStartTiMe);
00125 
00126   update();
00127   changeParentTotalTimes( mSessionTime, mTime);
00128   
00129   // alignment of the number items
00130   for (int i = 1; i < columnCount(); ++i) 
00131   {
00132       setTextAlignment( i, Qt::AlignRight );
00133   }
00134 
00135   // .. but not the priority column
00136   setTextAlignment( 5, Qt::AlignCenter );
00137 }
00138 
00139 Task::~Task() 
00140 {
00141   emit deletingTask(this);
00142   delete mTimer;
00143 }
00144 
00145 void Task::delete_recursive()
00146 {
00147   while ( this->child(0) )
00148   {
00149     Task* t=(Task*) this->child(0);
00150     t->delete_recursive();
00151   }
00152   delete this;
00153 }
00154 
00155 void Task::setRunning( bool on, KarmStorage* storage, const QDateTime &when )
00156 // This is the back-end, the front-end is StartTimerFor()
00157 {
00158   kDebug(5970) << "Entering function"; 
00159   if ( on ) 
00160   {
00161     if (!mTimer->isActive()) 
00162     {
00163       mTimer->start(1000);
00164       storage->startTimer(this);
00165       mCurrentPic=7;
00166       mLastStart = when;
00167       kDebug(5970) << "task has been started for " << when;
00168       updateActiveIcon();
00169     }
00170   }
00171   else 
00172   {
00173     if (mTimer->isActive()) 
00174     {
00175       mTimer->stop();
00176       if ( ! mRemoving ) 
00177       {
00178         storage->stopTimer(this, when);
00179         setIcon(1, UserIcon(QString::fromLatin1("empty-watch.xpm")));
00180       }
00181     }
00182   }
00183 }
00184 
00185 void Task::resumeRunning()
00186 // setRunning is the back-end, the front-end is StartTimerFor().
00187 // resumeRunning does the same as setRunning, but not add a new 
00188 // start date to the storage.
00189 {
00190   kDebug(5970) << "Entering function"; 
00191   if (!mTimer->isActive()) 
00192   {
00193     mTimer->start(1000);
00194     mCurrentPic=7;
00195     updateActiveIcon();
00196   }
00197 }
00198 
00199 void Task::setUid( const QString &uid ) 
00200 {
00201   mUid = uid;
00202 }
00203 
00204 bool Task::isRunning() const
00205 {
00206   return mTimer->isActive();
00207 }
00208 
00209 void Task::setName( const QString& name, KarmStorage* storage )
00210 {
00211   kDebug(5970) << "Entering function, name=" << name;
00212 
00213   QString oldname = mName;
00214   if ( oldname != name ) 
00215   {
00216     mName = name;
00217     storage->setName(this, oldname);
00218     update();
00219   }
00220 }
00221 
00222 void Task::setPercentComplete(const int percent, KarmStorage *storage)
00223 {
00224   kDebug(5970) << "Entering function(" << percent <<", storage):"
00225     << mUid;
00226 
00227   if (!percent)
00228     mPercentComplete = 0;
00229   else if (percent > 100)
00230     mPercentComplete = 100;
00231   else if (percent < 0)
00232     mPercentComplete = 0;
00233   else
00234     mPercentComplete = percent;
00235 
00236   if (isRunning() && mPercentComplete==100) taskView()->stopTimerFor(this);
00237 
00238   setPixmapProgress();
00239 
00240   // When parent marked as complete, mark all children as complete as well.
00241   // This behavior is consistent with KOrganizer (as of 2003-09-24).
00242   if (mPercentComplete == 100)
00243   {
00244     for ( int i = 0; i < childCount(); ++i ) {
00245       Task *task = static_cast< Task* >( child( i ) );
00246       task->setPercentComplete(mPercentComplete, storage);
00247     }
00248   }
00249   // maybe there is a column "percent completed", so do a ...
00250   update();
00251 }
00252 
00253 void Task::setPriority( int priority )
00254 {
00255   if ( priority < 0 ) 
00256   {
00257     priority = 0;
00258   } 
00259   else if ( priority > 9 ) 
00260   {
00261     priority = 9;
00262   }
00263 
00264   mPriority = priority;
00265   update();
00266 }
00267 
00268 void Task::setPixmapProgress()
00269 {
00270   QPixmap icon;
00271   if (mPercentComplete >= 100)
00272     icon = UserIcon("task-complete.xpm");
00273   else
00274     icon = UserIcon("task-incomplete.xpm");
00275   setIcon(0, icon);
00276 }
00277 
00278 bool Task::isComplete() { return mPercentComplete == 100; }
00279 
00280 void Task::setDesktopList ( DesktopList desktopList )
00281 {
00282   mDesktops = desktopList;
00283 }
00284 
00285 void Task::changeTime( long minutes, KarmStorage* storage )
00286 {
00287   changeTimes( minutes, minutes, storage); 
00288 }
00289 
00290 QString Task::addTime( long minutes )
00291 {
00292   kDebug(5970) << "Entering function";
00293   QString err;
00294   mTime+=minutes;
00295   this->addTotalTime( minutes );
00296   kDebug(5970) << "Leaving function";
00297   return err;
00298 }
00299 
00300 QString Task::addTotalTime( long minutes )
00301 {
00302   kDebug(5970) << "Entering function";
00303   QString err;
00304   mTotalTime+=minutes;
00305   if ( parent() ) parent()->addTotalTime( minutes );
00306   kDebug(5970) << "Leaving function";
00307   return err;
00308 }
00309 
00310 QString Task::addSessionTime( long minutes )
00311 {
00312   kDebug(5970) << "Entering function";
00313   QString err;
00314   mSessionTime+=minutes;
00315   this->addTotalSessionTime( minutes );
00316   kDebug(5970) << "Leaving function";
00317   return err;
00318 }
00319 
00320 QString Task::addTotalSessionTime( long minutes )
00321 {
00322   kDebug(5970) << "Entering function";
00323   QString err;
00324   mTotalSessionTime+=minutes;
00325   if ( parent() ) parent()->addTotalSessionTime( minutes );
00326   kDebug(5970) << "Leaving function";
00327   return err;
00328 }
00329 
00330 QString Task::setTime( long minutes )
00331 {
00332   kDebug(5970) << "Entering function";
00333   QString err;
00334   mTime=minutes;
00335   mTotalTime+=minutes;
00336   kDebug(5970) << "Leaving function";
00337   return err;
00338 }
00339 
00340 QString Task::setSessionTime( long minutes )
00341 {
00342   kDebug(5970) << "Entering function";
00343   QString err;
00344   mSessionTime=minutes;
00345   mTotalSessionTime+=minutes;
00346   kDebug(5970) << "Leaving function";
00347   return err;
00348 }
00349 
00350 void Task::changeTimes( long minutesSession, long minutes, KarmStorage* storage)
00351 {
00352   kDebug(5970) << "Entering function";
00353   kDebug() << "Task's sessionStartTiMe is " << mSessionStartTiMe;
00354   if( minutesSession != 0 || minutes != 0) 
00355   {
00356     mSessionTime += minutesSession;
00357     mTime += minutes;
00358     if ( storage ) storage->changeTime(this, minutes * secsPerMinute);
00359     changeTotalTimes( minutesSession, minutes );
00360   }
00361   kDebug(5970) << "Leaving function";
00362 }
00363 
00364 void Task::changeTotalTimes( long minutesSession, long minutes )
00365 {
00366   kDebug(5970)
00367     << "Task::changeTotalTimes(" << minutesSession << ","
00368     << minutes << ") for" << name();
00369 
00370   mTotalSessionTime += minutesSession;
00371   mTotalTime += minutes;
00372   update();
00373   changeParentTotalTimes( minutesSession, minutes );
00374   kDebug(5970) <<"Leaving function";
00375 }
00376 
00377 void Task::resetTimes()
00378 {
00379   kDebug(5970) <<"Entering function";
00380   mTotalSessionTime -= mSessionTime;
00381   mTotalTime -= mTime;
00382   changeParentTotalTimes( -mSessionTime, -mTime);
00383   mSessionTime = 0;
00384   mTime = 0;
00385   update();
00386   kDebug(5970) <<"Leaving function";
00387 }
00388 
00389 void Task::changeParentTotalTimes( long minutesSession, long minutes )
00390 {
00391   if ( isRoot() )
00392     emit totalTimesChanged( minutesSession, minutes );
00393   else
00394     parent()->changeTotalTimes( minutesSession, minutes );
00395 }
00396 
00397 bool Task::remove( KarmStorage* storage)
00398 {
00399   kDebug(5970) <<"Task::remove:" << mName;
00400 
00401   bool ok = true;
00402 
00403   mRemoving = true;
00404   storage->removeTask(this);
00405   if( isRunning() ) setRunning( false, storage );
00406 
00407   for ( int i = 0; i < childCount(); ++i ) 
00408   {
00409     Task *task = static_cast< Task* >( child( i ) );
00410     if ( task->isRunning() )
00411       task->setRunning( false, storage );
00412     task->remove( storage );
00413   }
00414 
00415   changeParentTotalTimes( -mSessionTime, -mTime);
00416 
00417   mRemoving = false;
00418 
00419   return ok;
00420 }
00421 
00422 void Task::updateActiveIcon()
00423 {
00424   mCurrentPic = (mCurrentPic+1) % 8;
00425   setIcon(1, *(*icons)[mCurrentPic]);
00426 }
00427 
00428 QString Task::fullName() const
00429 {
00430   if (isRoot())
00431     return name();
00432   else
00433     return parent()->fullName() + QString::fromLatin1("/") + name();
00434 }
00435 
00436 KCal::Todo* Task::asTodo(KCal::Todo* todo) const
00437 {
00438 
00439   Q_ASSERT( todo != NULL );
00440 
00441   kDebug(5970) <<"Task::asTodo: name() = '" << name() <<"'";
00442   todo->setSummary( name() );
00443 
00444   // Note: if the date start is empty, the KOrganizer GUI will have the
00445   // checkbox blank, but will prefill the todo's starting datetime to the
00446   // time the file is opened.
00447   // todo->setDtStart( current );
00448 
00449   todo->setCustomProperty( KGlobal::mainComponent().componentName().toUtf8(),
00450       QByteArray( "totalTaskTime" ), QString::number( mTime ) );
00451   todo->setCustomProperty( KGlobal::mainComponent().componentName().toUtf8(),
00452       QByteArray( "totalSessionTime" ), QString::number( mSessionTime) );
00453   todo->setCustomProperty( KGlobal::mainComponent().componentName().toUtf8(),
00454       QByteArray( "sessionStartTiMe" ), mSessionStartTiMe.toString() );
00455   kDebug() << "mSessionStartTiMe=" << mSessionStartTiMe.toString() ;
00456 
00457   if (getDesktopStr().isEmpty())
00458     todo->removeCustomProperty(KGlobal::mainComponent().componentName().toUtf8(), QByteArray("desktopList"));
00459   else
00460     todo->setCustomProperty( KGlobal::mainComponent().componentName().toUtf8(),
00461         QByteArray( "desktopList" ), getDesktopStr() );
00462 
00463   todo->setOrganizer( KTimeTrackerSettings::userRealName() );
00464 
00465   todo->setPercentComplete(mPercentComplete);
00466   todo->setPriority( mPriority );
00467 
00468   return todo;
00469 }
00470 
00471 bool Task::parseIncidence( KCal::Incidence* incident, long& minutes,
00472     long& sessionMinutes, QString& sessionStartTiMe, QString& name, DesktopList& desktops,
00473     int& percent_complete, int& priority )
00474 {
00475   kDebug(5970) << "Entering function";
00476   bool ok;
00477 
00478   name = incident->summary();
00479   mUid = incident->uid();
00480 
00481   mComment = incident->description();
00482 
00483   ok = false;
00484 
00485   // if a KDE-karm-duration exists and not KDE-ktimetracker-duration, change this
00486   if (
00487   incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(),
00488       QByteArray( "totalTaskTime" )) == QString::null && incident->customProperty( "karm",
00489       QByteArray( "totalTaskTime" )) != QString::null )
00490     incident->setCustomProperty(  
00491       KGlobal::mainComponent().componentName().toUtf8(),
00492       QByteArray( "totalTaskTime" ), incident->customProperty( "karm",
00493       QByteArray( "totalTaskTime" )));
00494 
00495   minutes = incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(),
00496       QByteArray( "totalTaskTime" )).toInt( &ok );
00497   if ( !ok )
00498     minutes = 0;
00499 
00500   ok = false;
00501 
00502   // if a KDE-karm-totalSessionTime exists and not KDE-ktimetracker-totalSessionTime, change this
00503   if (
00504   incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(),
00505       QByteArray( "totalSessionTime" )) == QString::null && incident->customProperty( "karm",
00506       QByteArray( "totalSessionTime" )) != QString::null )
00507     incident->setCustomProperty(  
00508       KGlobal::mainComponent().componentName().toUtf8(),
00509       QByteArray( "totalSessionTime" ), incident->customProperty( "karm",
00510       QByteArray( "totalSessionTime" )));
00511 
00512   sessionMinutes = incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(),
00513       QByteArray( "totalSessionTime" )).toInt( &ok );
00514   if ( !ok )
00515     sessionMinutes = 0;
00516   sessionStartTiMe=incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(), QByteArray( "sessionStartTiMe" ));
00517 
00518   // if a KDE-karm-deskTopList exists and no KDE-ktimetracker-DeskTopList, change this
00519   if (
00520   incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(),
00521       QByteArray( "desktopList" )) == QString::null && incident->customProperty( "karm",
00522       QByteArray( "desktopList" )) != QString::null )
00523     incident->setCustomProperty(  
00524       KGlobal::mainComponent().componentName().toUtf8(),
00525       QByteArray( "desktopList" ), incident->customProperty( "karm",
00526       QByteArray( "desktopList" )));
00527 
00528   QString desktopList = incident->customProperty( KGlobal::mainComponent().componentName().toUtf8(),
00529       QByteArray( "desktopList" ) );
00530   QStringList desktopStrList = desktopList.split( QString::fromLatin1(","),
00531       QString::SkipEmptyParts );
00532   desktops.clear();
00533 
00534   for ( QStringList::iterator iter = desktopStrList.begin();
00535         iter != desktopStrList.end();
00536         ++iter ) {
00537     int desktopInt = (*iter).toInt( &ok );
00538     if ( ok ) {
00539       desktops.push_back( desktopInt );
00540     }
00541   }
00542 
00543   percent_complete = static_cast<KCal::Todo*>(incident)->percentComplete();
00544   priority = incident->priority();
00545   return true;
00546 }
00547 
00548 QString Task::getDesktopStr() const
00549 {
00550   if ( mDesktops.empty() )
00551     return QString();
00552 
00553   QString desktopstr;
00554   for ( DesktopList::const_iterator iter = mDesktops.begin();
00555         iter != mDesktops.end();
00556         ++iter ) {
00557     desktopstr += QString::number( *iter ) + QString::fromLatin1( "," );
00558   }
00559   desktopstr.remove( desktopstr.length() - 1, 1 );
00560   return desktopstr;
00561 }
00562 
00563 void Task::cut()
00564 // This is needed e.g. to move a task under its parent when loading.
00565 {
00566   kDebug(5970) << "Entering function";
00567   changeParentTotalTimes( -mTotalSessionTime, -mTotalTime);
00568   if ( ! parent() )
00569     treeWidget()->takeTopLevelItem(treeWidget()->indexOfTopLevelItem(this));
00570   else
00571     parent()->takeChild(indexOfChild(this));
00572   kDebug(5970) << "Leaving function";
00573 }
00574 
00575 void Task::paste(Task* destination)
00576 // This is needed e.g. to move a task under its parent when loading.
00577 {
00578   kDebug(5970) << "Entering function";
00579   destination->QTreeWidgetItem::insertChild(0,this);
00580   changeParentTotalTimes( mTotalSessionTime, mTotalTime);
00581   kDebug(5970) << "Leaving function";
00582 }
00583 
00584 void Task::move(Task* destination)
00585 // This is used e.g. to move each task under its parent after loading.
00586 {
00587   kDebug(5970) << "Entering function";
00588   cut();
00589   paste(destination);
00590   kDebug(5970) << "Leaving function";
00591 }
00592 
00593 void Task::update()
00594 // Update a row, containing one task
00595 {
00596   kDebug( 5970 ) << "Entering function";
00597   bool b = KTimeTrackerSettings::decimalFormat();
00598   setText( 0, mName );
00599   setText( 1, formatTime( mSessionTime, b ) );
00600   setText( 2, formatTime( mTime, b ) );
00601   setText( 3, formatTime( mTotalSessionTime, b ) );
00602   setText( 4, formatTime( mTotalTime, b ) );
00603   setText( 5, mPriority > 0 ? QString::number( mPriority ) : "--" );
00604   setText( 6, QString::number( mPercentComplete ) );
00605   kDebug( 5970 ) << "Leaving function";
00606 }
00607 
00608 void Task::addComment( const QString &comment, KarmStorage* storage )
00609 {
00610   mComment = mComment + QString::fromLatin1("\n") + comment;
00611   storage->addComment(this, comment);
00612 }
00613 
00614 void Task::startNewSession()
00615 {
00616   changeTimes( -mSessionTime, 0 );
00617   mSessionStartTiMe=KDateTime::currentLocalDateTime();
00618 }
00619 
00620 //BEGIN Properties
00621 QString Task::uid() const
00622 {
00623   return mUid;
00624 }
00625 
00626 QString Task::comment() const
00627 {
00628   return mComment;
00629 }
00630 
00631 int Task::percentComplete() const
00632 {
00633   return mPercentComplete;
00634 }
00635 
00636 int Task::priority() const
00637 {
00638   return mPriority;
00639 }
00640 
00641 QString Task::name() const
00642 {
00643   return mName;
00644 }
00645 
00646 QDateTime Task::startTime() const
00647 {
00648   return mLastStart;
00649 }
00650 
00651 long Task::time() const
00652 {
00653   return mTime;
00654 }
00655 
00656 long Task::totalTime() const
00657 {
00658   return mTotalTime;
00659 }
00660 
00661 long Task::sessionTime() const
00662 {
00663   return mSessionTime;
00664 }
00665 
00666 long Task::totalSessionTime() const
00667 {
00668   return mTotalSessionTime;
00669 }
00670 
00671 KDateTime Task::sessionStartTiMe() const
00672 {
00673   return mSessionStartTiMe;
00674 }
00675 
00676 DesktopList Task::desktops() const
00677 {
00678   return mDesktops;
00679 }
00680 //END
00681 
00682 #include "task.moc"

ktimetracker

Skip menu "ktimetracker"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal