• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

KCal Library

todo.cpp
Go to the documentation of this file.
00001 /*
00002   This file is part of the kcal library.
00003 
00004   Copyright (c) 2001-2003 Cornelius Schumacher <schumacher@kde.org>
00005   Copyright (C) 2009 Allen Winter <winter@kde.org>
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 */
00034 #include "todo.h"
00035 #include "incidenceformatter.h"
00036 
00037 #include <kglobal.h>
00038 #include <klocale.h>
00039 #include <kdebug.h>
00040 #include <ksystemtimezone.h>
00041 
00042 using namespace KCal;
00043 
00048 //@cond PRIVATE
00049 class KCal::Todo::Private
00050 {
00051   public:
00052     Private()
00053       : mPercentComplete( 0 ),
00054         mHasDueDate( false ),
00055         mHasStartDate( false ),
00056         mHasCompletedDate( false )
00057     {}
00058     Private( const KCal::Todo::Private &other )
00059     { init( other ); }
00060 
00061     void init( const KCal::Todo::Private &other );
00062 
00063     KDateTime mDtDue;        // to-do due date (if there is one)
00064                              // ALSO the first occurrence of a recurring to-do
00065     KDateTime mDtRecurrence; // next occurrence (for recurring to-dos)
00066     KDateTime mCompleted;    // to-do completion date (if it has been completed)
00067     int mPercentComplete;    // to-do percent complete [0,100]
00068     bool mHasDueDate;        // true if the to-do has a due date
00069     bool mHasStartDate;      // true if the to-do has a starting date
00070     bool mHasCompletedDate;  // true if the to-do has a completion date
00071 
00075     bool recurTodo( Todo *todo );
00076 };
00077 
00078 void KCal::Todo::Private::init( const KCal::Todo::Private &other )
00079 {
00080   mDtDue = other.mDtDue;
00081   mDtRecurrence = other.mDtRecurrence;
00082   mCompleted = other.mCompleted;
00083   mPercentComplete = other.mPercentComplete;
00084   mHasDueDate = other.mHasDueDate;
00085   mHasStartDate = other.mHasStartDate;
00086   mHasCompletedDate = other.mHasCompletedDate;
00087 }
00088 
00089 //@endcond
00090 
00091 Todo::Todo()
00092   : d( new KCal::Todo::Private )
00093 {
00094 }
00095 
00096 Todo::Todo( const Todo &other )
00097   : Incidence( other ),
00098     d( new KCal::Todo::Private( *other.d ) )
00099 {
00100 }
00101 
00102 Todo::~Todo()
00103 {
00104   delete d;
00105 }
00106 
00107 Todo *Todo::clone()
00108 {
00109   return new Todo( *this );
00110 }
00111 
00112 Todo &Todo::operator=( const Todo &other )
00113 {
00114   // check for self assignment
00115   if ( &other == this ) {
00116     return *this;
00117   }
00118 
00119   Incidence::operator=( other );
00120   d->init( *other.d );
00121   return *this;
00122 }
00123 
00124 bool Todo::operator==( const Todo &todo ) const
00125 {
00126   return
00127     Incidence::operator==( todo ) &&
00128     dtDue() == todo.dtDue() &&
00129     hasDueDate() == todo.hasDueDate() &&
00130     hasStartDate() == todo.hasStartDate() &&
00131     completed() == todo.completed() &&
00132     hasCompletedDate() == todo.hasCompletedDate() &&
00133     percentComplete() == todo.percentComplete();
00134 }
00135 
00136 QByteArray Todo::type() const
00137 {
00138   return "Todo";
00139 }
00140 
00141 //KDE5:
00142 //QString Todo::typeStr() const
00143 //{
00144 //  return i18nc( "incidence type is to-do/task", "to-do" );
00145 //}
00146 
00147 void Todo::setDtDue( const KDateTime &dtDue, bool first )
00148 {
00149   //int diffsecs = d->mDtDue.secsTo(dtDue);
00150 
00151   /*if (mReadOnly) return;
00152   const Alarm::List& alarms = alarms();
00153   for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) {
00154     if (alarm->enabled()) {
00155       alarm->setTime(alarm->time().addSecs(diffsecs));
00156     }
00157   }*/
00158 
00159   d->mHasDueDate = true;
00160   if ( recurs() && !first ) {
00161     d->mDtRecurrence = dtDue;
00162   } else {
00163     d->mDtDue = dtDue;
00164     // TODO: This doesn't seem right...
00165     recurrence()->setStartDateTime( dtDue );
00166     recurrence()->setAllDay( allDay() );
00167   }
00168 
00169   if ( recurs() && dtDue < recurrence()->startDateTime() ) {
00170     setDtStart( dtDue );
00171   }
00172 
00173   /*const Alarm::List& alarms = alarms();
00174   for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next())
00175     alarm->setAlarmStart(d->mDtDue);*/
00176 
00177   updated();
00178 }
00179 
00180 KDateTime Todo::dtDue( bool first ) const
00181 {
00182   if ( !hasDueDate() ) {
00183     return KDateTime();
00184   }
00185   if ( recurs() && !first && d->mDtRecurrence.isValid() ) {
00186     return d->mDtRecurrence;
00187   }
00188 
00189   return d->mDtDue;
00190 }
00191 
00192 QString Todo::dtDueTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
00193 {
00194   if ( spec.isValid() ) {
00195 
00196     QString timeZone;
00197     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00198       timeZone = ' ' + spec.timeZone().name();
00199     }
00200 
00201     return KGlobal::locale()->formatTime(
00202       dtDue( !recurs() ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
00203   } else {
00204     return KGlobal::locale()->formatTime(
00205       dtDue( !recurs() ).time(), !shortfmt );
00206   }
00207 }
00208 
00209 QString Todo::dtDueDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
00210 {
00211   if ( spec.isValid() ) {
00212 
00213     QString timeZone;
00214     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00215       timeZone = ' ' + spec.timeZone().name();
00216     }
00217 
00218     return KGlobal::locale()->formatDate(
00219       dtDue( !recurs() ).toTimeSpec( spec ).date(),
00220       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
00221   } else {
00222     return KGlobal::locale()->formatDate(
00223       dtDue( !recurs() ).date(),
00224       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00225   }
00226 }
00227 
00228 QString Todo::dtDueStr( bool shortfmt, const KDateTime::Spec &spec ) const
00229 {
00230   if ( allDay() ) {
00231     return IncidenceFormatter::dateToString( dtDue(), shortfmt, spec );
00232   }
00233 
00234   if ( spec.isValid() ) {
00235 
00236     QString timeZone;
00237     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00238       timeZone = ' ' + spec.timeZone().name();
00239     }
00240 
00241     return KGlobal::locale()->formatDateTime(
00242       dtDue( !recurs() ).toTimeSpec( spec ).dateTime(),
00243       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
00244   } else {
00245     return  KGlobal::locale()->formatDateTime(
00246       dtDue( !recurs() ).dateTime(),
00247       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00248   }
00249 }
00250 
00251 bool Todo::hasDueDate() const
00252 {
00253   return d->mHasDueDate;
00254 }
00255 
00256 void Todo::setHasDueDate( bool f )
00257 {
00258   if ( mReadOnly ) {
00259     return;
00260   }
00261   d->mHasDueDate = f;
00262   updated();
00263 }
00264 
00265 bool Todo::hasStartDate() const
00266 {
00267   return d->mHasStartDate;
00268 }
00269 
00270 void Todo::setHasStartDate( bool f )
00271 {
00272   if ( mReadOnly ) {
00273     return;
00274   }
00275 
00276   if ( recurs() && !f ) {
00277     if ( !comments().filter( "NoStartDate" ).count() ) {
00278       addComment( "NoStartDate" ); //TODO: --> custom flag?
00279     }
00280   } else {
00281     QString s( "NoStartDate" );
00282     removeComment( s );
00283   }
00284   d->mHasStartDate = f;
00285   updated();
00286 }
00287 
00288 KDateTime Todo::dtStart() const
00289 {
00290   return dtStart( false );
00291 }
00292 
00293 KDateTime Todo::dtStart( bool first ) const
00294 {
00295   if ( !hasStartDate() ) {
00296     return KDateTime();
00297   }
00298   if ( recurs() && !first ) {
00299     KDateTime dt = d->mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
00300     dt.setTime( IncidenceBase::dtStart().time() );
00301     return dt;
00302   } else {
00303     return IncidenceBase::dtStart();
00304   }
00305 }
00306 
00307 void Todo::setDtStart( const KDateTime &dtStart )
00308 {
00309   // TODO: This doesn't seem right (rfc 2445/6 says, recurrence is calculated from the dtstart...)
00310   if ( recurs() ) {
00311     recurrence()->setStartDateTime( d->mDtDue );
00312     recurrence()->setAllDay( allDay() );
00313   }
00314   d->mHasStartDate = true;
00315   IncidenceBase::setDtStart( dtStart );
00316 }
00317 
00318 QString Todo::dtStartTimeStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
00319 {
00320   if ( spec.isValid() ) {
00321 
00322     QString timeZone;
00323     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00324       timeZone = ' ' + spec.timeZone().name();
00325     }
00326 
00327     return KGlobal::locale()->formatTime(
00328       dtStart( first ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
00329   } else {
00330     return KGlobal::locale()->formatTime(
00331       dtStart( first ).time(), !shortfmt );
00332   }
00333 }
00334 
00335 QString Todo::dtStartTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
00336 {
00337   return IncidenceFormatter::timeToString( dtStart(), shortfmt, spec );
00338 }
00339 
00340 QString Todo::dtStartDateStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
00341 {
00342   if ( spec.isValid() ) {
00343 
00344     QString timeZone;
00345     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00346       timeZone = ' ' + spec.timeZone().name();
00347     }
00348 
00349     return KGlobal::locale()->formatDate(
00350       dtStart( first ).toTimeSpec( spec ).date(),
00351       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
00352   } else {
00353     return KGlobal::locale()->formatDate(
00354       dtStart( first ).date(),
00355       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00356   }
00357 }
00358 
00359 QString Todo::dtStartDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
00360 {
00361   return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec );
00362 }
00363 
00364 QString Todo::dtStartStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
00365 {
00366   if ( allDay() ) {
00367     return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec );
00368   }
00369 
00370   if ( spec.isValid() ) {
00371 
00372     QString timeZone;
00373     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00374       timeZone = ' ' + spec.timeZone().name();
00375     }
00376 
00377     return KGlobal::locale()->formatDateTime(
00378       dtStart( first ).toTimeSpec( spec ).dateTime(),
00379       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
00380   } else {
00381     return KGlobal::locale()->formatDateTime(
00382       dtStart( first ).dateTime(),
00383       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00384   }
00385 }
00386 
00387 QString Todo::dtStartStr( bool shortfmt, const KDateTime::Spec &spec ) const
00388 {
00389   if ( allDay() ) {
00390     return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec );
00391   }
00392 
00393   if ( spec.isValid() ) {
00394 
00395     QString timeZone;
00396     if ( spec.timeZone() != KSystemTimeZones::local() ) {
00397       timeZone = ' ' + spec.timeZone().name();
00398     }
00399 
00400     return KGlobal::locale()->formatDateTime(
00401       dtStart().toTimeSpec( spec ).dateTime(),
00402       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
00403   } else {
00404     return KGlobal::locale()->formatDateTime(
00405       dtStart().dateTime(),
00406       ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00407   }
00408 }
00409 
00410 bool Todo::isCompleted() const
00411 {
00412   if ( d->mPercentComplete == 100 ) {
00413     return true;
00414   } else {
00415     return false;
00416   }
00417 }
00418 
00419 void Todo::setCompleted( bool completed )
00420 {
00421   if ( completed ) {
00422     d->mPercentComplete = 100;
00423   } else {
00424     d->mPercentComplete = 0;
00425     d->mHasCompletedDate = false;
00426     d->mCompleted = KDateTime();
00427   }
00428   updated();
00429 }
00430 
00431 KDateTime Todo::completed() const
00432 {
00433   if ( hasCompletedDate() ) {
00434     return d->mCompleted;
00435   } else {
00436     return KDateTime();
00437   }
00438 }
00439 
00440 QString Todo::completedStr( bool shortfmt ) const
00441 {
00442   return
00443     KGlobal::locale()->formatDateTime( d->mCompleted.dateTime(),
00444                                        ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00445 }
00446 
00447 void Todo::setCompleted( const KDateTime &completed )
00448 {
00449   if ( !d->recurTodo( this ) ) {
00450     d->mHasCompletedDate = true;
00451     d->mPercentComplete = 100;
00452     d->mCompleted = completed.toUtc();
00453   }
00454   updated();
00455 }
00456 
00457 bool Todo::hasCompletedDate() const
00458 {
00459   return d->mHasCompletedDate;
00460 }
00461 
00462 int Todo::percentComplete() const
00463 {
00464   return d->mPercentComplete;
00465 }
00466 
00467 void Todo::setPercentComplete( int percent )
00468 {
00469   //TODO: (?) assert percent between 0 and 100, inclusive
00470   d->mPercentComplete = percent;
00471   if ( percent != 100 ) {
00472     d->mHasCompletedDate = false;
00473   }
00474   updated();
00475 }
00476 
00477 bool Todo::isInProgress( bool first ) const
00478 {
00479   if ( isOverdue() ) {
00480     return false;
00481   }
00482 
00483   if ( d->mPercentComplete > 0 ) {
00484     return true;
00485   }
00486 
00487   if ( d->mHasStartDate && d->mHasDueDate ) {
00488     if ( allDay() ) {
00489       QDate currDate = QDate::currentDate();
00490       if ( dtStart( first ).date() <= currDate && currDate < dtDue( first ).date() ) {
00491         return true;
00492       }
00493     } else {
00494       KDateTime currDate = KDateTime::currentUtcDateTime();
00495       if ( dtStart( first ) <= currDate && currDate < dtDue( first ) ) {
00496         return true;
00497       }
00498     }
00499   }
00500 
00501   return false;
00502 }
00503 
00504 bool Todo::isOpenEnded() const
00505 {
00506   if ( !d->mHasDueDate && !isCompleted() ) {
00507     return true;
00508   }
00509   return false;
00510 
00511 }
00512 
00513 bool Todo::isNotStarted( bool first ) const
00514 {
00515   if ( d->mPercentComplete > 0 ) {
00516     return false;
00517   }
00518 
00519   if ( !d->mHasStartDate ) {
00520     return false;
00521   }
00522 
00523   if ( allDay() ) {
00524     if ( dtStart( first ).date() >= QDate::currentDate() ) {
00525       return false;
00526     }
00527   } else {
00528     if ( dtStart( first ) >= KDateTime::currentUtcDateTime() ) {
00529       return false;
00530     }
00531   }
00532   return true;
00533 }
00534 
00535 void Todo::shiftTimes( const KDateTime::Spec &oldSpec,
00536                        const KDateTime::Spec &newSpec )
00537 {
00538   Incidence::shiftTimes( oldSpec, newSpec );
00539   d->mDtDue = d->mDtDue.toTimeSpec( oldSpec );
00540   d->mDtDue.setTimeSpec( newSpec );
00541   if ( recurs() ) {
00542     d->mDtRecurrence = d->mDtRecurrence.toTimeSpec( oldSpec );
00543     d->mDtRecurrence.setTimeSpec( newSpec );
00544   }
00545   if ( d->mHasCompletedDate ) {
00546     d->mCompleted = d->mCompleted.toTimeSpec( oldSpec );
00547     d->mCompleted.setTimeSpec( newSpec );
00548   }
00549 }
00550 
00551 void Todo::setDtRecurrence( const KDateTime &dt )
00552 {
00553   d->mDtRecurrence = dt;
00554 }
00555 
00556 KDateTime Todo::dtRecurrence() const
00557 {
00558   return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
00559 }
00560 
00561 bool Todo::recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const
00562 {
00563   QDate today = QDate::currentDate();
00564   return
00565     Incidence::recursOn( date, timeSpec ) &&
00566     !( date < today && d->mDtRecurrence.date() < today &&
00567        d->mDtRecurrence > recurrence()->startDateTime() );
00568 }
00569 
00570 bool Todo::isOverdue() const
00571 {
00572   if ( !dtDue().isValid() ) {
00573     return false; // if it's never due, it can't be overdue
00574   }
00575 
00576   bool inPast = allDay() ?
00577                 dtDue().date() < QDate::currentDate() :
00578                 dtDue() < KDateTime::currentUtcDateTime();
00579   return inPast && !isCompleted();
00580 }
00581 
00582 KDateTime Todo::endDateRecurrenceBase() const
00583 {
00584   return dtDue();
00585 }
00586 
00587 //@cond PRIVATE
00588 bool Todo::Private::recurTodo( Todo *todo )
00589 {
00590   if ( todo->recurs() ) {
00591     Recurrence *r = todo->recurrence();
00592     KDateTime endDateTime = r->endDateTime();
00593     KDateTime nextDate = r->getNextDateTime( todo->dtDue() );
00594 
00595     if ( ( r->duration() == -1 ||
00596            ( nextDate.isValid() && endDateTime.isValid() &&
00597              nextDate <= endDateTime ) ) ) {
00598 
00599       while ( !todo->recursAt( nextDate ) ||
00600               nextDate <= KDateTime::currentUtcDateTime() ) {
00601 
00602         if ( !nextDate.isValid() ||
00603              ( nextDate > endDateTime && r->duration() != -1 ) ) {
00604 
00605           return false;
00606         }
00607 
00608         nextDate = r->getNextDateTime( nextDate );
00609       }
00610 
00611       todo->setDtDue( nextDate );
00612       todo->setCompleted( false );
00613       todo->setRevision( todo->revision() + 1 );
00614 
00615       return true;
00616     }
00617   }
00618 
00619   return false;
00620 }
00621 //@endcond

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.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