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

KCalCore Library

todo.cpp

Go to the documentation of this file.
00001 /*
00002   This file is part of the kcalcore 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 "visitor.h"
00036 
00037 using namespace KCalCore;
00038 
00043 //@cond PRIVATE
00044 class KCalCore::Todo::Private
00045 {
00046   public:
00047     Private()
00048       : mPercentComplete( 0 ),
00049         mHasDueDate( false ),
00050         mHasStartDate( false ),
00051         mHasCompletedDate( false )
00052     {}
00053     Private( const KCalCore::Todo::Private &other )
00054     { init( other ); }
00055 
00056     void init( const KCalCore::Todo::Private &other );
00057 
00058     KDateTime mDtDue;        // to-do due date (if there is one)
00059                              // ALSO the first occurrence of a recurring to-do
00060     KDateTime mDtRecurrence; // next occurrence (for recurring to-dos)
00061     KDateTime mCompleted;    // to-do completion date (if it has been completed)
00062     int mPercentComplete;    // to-do percent complete [0,100]
00063     bool mHasDueDate;        // true if the to-do has a due date
00064     bool mHasStartDate;      // true if the to-do has a starting date
00065     bool mHasCompletedDate;  // true if the to-do has a completion date
00066 
00070    bool recurTodo( Todo *todo );
00071 };
00072 
00073 void KCalCore::Todo::Private::init( const KCalCore::Todo::Private &other )
00074 {
00075   mDtDue = other.mDtDue;
00076   mDtRecurrence = other.mDtRecurrence;
00077   mCompleted = other.mCompleted;
00078   mPercentComplete = other.mPercentComplete;
00079   mHasDueDate = other.mHasDueDate;
00080   mHasStartDate = other.mHasStartDate;
00081   mHasCompletedDate = other.mHasCompletedDate;
00082 }
00083 
00084 //@endcond
00085 
00086 Todo::Todo()
00087   : d( new KCalCore::Todo::Private )
00088 {
00089 }
00090 
00091 Todo::Todo( const Todo &other )
00092   : Incidence( other ),
00093     d( new KCalCore::Todo::Private( *other.d ) )
00094 {
00095 }
00096 
00097 Todo::~Todo()
00098 {
00099   delete d;
00100 }
00101 
00102 Todo *Todo::clone() const
00103 {
00104   return new Todo( *this );
00105 }
00106 
00107 IncidenceBase &Todo::assign( const IncidenceBase &other )
00108 {
00109   if ( &other != this ) {
00110     Incidence::assign( other );
00111     const Todo *t = static_cast<const Todo*>( &other );
00112     d->init( *( t->d ) );
00113   }
00114   return *this;
00115 }
00116 
00117 bool Todo::equals( const IncidenceBase &todo ) const
00118 {
00119   if ( !Incidence::equals( todo ) ) {
00120     return false;
00121   } else {
00122     // If they weren't the same type IncidenceBase::equals would had returned false already
00123     const Todo *t = static_cast<const Todo*>( &todo );
00124     return ( ( dtDue() == t->dtDue() ) ||
00125              ( !dtDue().isValid() && !t->dtDue().isValid() ) ) &&
00126       hasDueDate() == t->hasDueDate() &&
00127       hasStartDate() == t->hasStartDate() &&
00128       ( ( completed() == t->completed() ) ||
00129         ( !completed().isValid() && !t->completed().isValid() ) ) &&
00130       hasCompletedDate() == t->hasCompletedDate() &&
00131       percentComplete() == t->percentComplete();
00132   }
00133 }
00134 
00135 Incidence::IncidenceType Todo::type() const
00136 {
00137   return TypeTodo;
00138 }
00139 
00140 QByteArray Todo::typeStr() const
00141 {
00142   return "Todo";
00143 }
00144 void Todo::setDtDue( const KDateTime &dtDue, bool first )
00145 {
00146   startUpdates();
00147 
00148   //int diffsecs = d->mDtDue.secsTo(dtDue);
00149 
00150   /*if (mReadOnly) return;
00151   const Alarm::List& alarms = alarms();
00152   for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) {
00153     if (alarm->enabled()) {
00154       alarm->setTime(alarm->time().addSecs(diffsecs));
00155     }
00156   }*/
00157   if ( dtDue.isValid() ) {
00158       d->mHasDueDate = true;
00159   } else {
00160       d->mHasDueDate = false;
00161   }
00162 
00163   if ( recurs() && !first ) {
00164     d->mDtRecurrence = dtDue;
00165   } else {
00166     d->mDtDue = dtDue;
00167     // TODO: This doesn't seem right...
00168     recurrence()->setStartDateTime( dtDue );
00169     recurrence()->setAllDay( allDay() );
00170   }
00171 
00172   if ( recurs() && dtDue < recurrence()->startDateTime() ) {
00173     setDtStart( dtDue );
00174   }
00175 
00176   /*const Alarm::List& alarms = alarms();
00177   for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next())
00178     alarm->setAlarmStart(d->mDtDue);*/
00179   setFieldDirty( FieldDtDue );
00180   endUpdates();
00181 }
00182 
00183 KDateTime Todo::dtDue( bool first ) const
00184 {
00185   if ( !hasDueDate() ) {
00186     return KDateTime();
00187   }
00188   if ( recurs() && !first && d->mDtRecurrence.isValid() ) {
00189     return d->mDtRecurrence;
00190   }
00191 
00192   return d->mDtDue;
00193 }
00194 
00195 bool Todo::hasDueDate() const
00196 {
00197   return d->mHasDueDate;
00198 }
00199 
00200 void Todo::setHasDueDate( bool f )
00201 {
00202   if ( mReadOnly ) {
00203     return;
00204   }
00205   update();
00206   d->mHasDueDate = f;
00207   setFieldDirty( FieldDtDue );
00208   updated();
00209 }
00210 
00211 bool Todo::hasStartDate() const
00212 {
00213   return d->mHasStartDate;
00214 }
00215 
00216 void Todo::setHasStartDate( bool f )
00217 {
00218   if ( mReadOnly ) {
00219     return;
00220   }
00221 
00222   update();
00223   if ( recurs() && !f ) {
00224     if ( !comments().filter( "NoStartDate" ).count() ) {
00225       addComment( "NoStartDate" ); //TODO: --> custom flag?
00226     }
00227   } else {
00228     QString s( "NoStartDate" );
00229     removeComment( s );
00230   }
00231   d->mHasStartDate = f;
00232   setFieldDirty( FieldDtStart );
00233   updated();
00234 }
00235 
00236 KDateTime Todo::dtStart() const
00237 {
00238   return dtStart( false );
00239 }
00240 
00241 KDateTime Todo::dtStart( bool first ) const
00242 {
00243   if ( !hasStartDate() ) {
00244     return KDateTime();
00245   }
00246   if ( recurs() && !first ) {
00247     KDateTime dt = d->mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
00248     dt.setTime( IncidenceBase::dtStart().time() );
00249     return dt;
00250   } else {
00251     return IncidenceBase::dtStart();
00252   }
00253 }
00254 
00255 void Todo::setDtStart( const KDateTime &dtStart )
00256 {
00257   // TODO: This doesn't seem right (rfc 2445/6 says, recurrence is calculated from the dtstart...)
00258 
00259   d->mHasStartDate = dtStart.isValid();
00260 
00261   if ( recurs() ) {
00262     recurrence()->setStartDateTime( d->mDtDue );
00263     recurrence()->setAllDay( allDay() );
00264   }
00265   IncidenceBase::setDtStart( dtStart );
00266 }
00267 
00268 bool Todo::isCompleted() const
00269 {
00270   return d->mPercentComplete == 100;
00271 }
00272 
00273 void Todo::setCompleted( bool completed )
00274 {
00275   update();
00276   if ( completed ) {
00277     d->mPercentComplete = 100;
00278   } else {
00279     d->mPercentComplete = 0;
00280     d->mHasCompletedDate = false;
00281     d->mCompleted = KDateTime();
00282   }
00283   setFieldDirty( FieldCompleted );
00284   updated();
00285 }
00286 
00287 KDateTime Todo::completed() const
00288 {
00289   if ( hasCompletedDate() ) {
00290     return d->mCompleted;
00291   } else {
00292     return KDateTime();
00293   }
00294 }
00295 
00296 void Todo::setCompleted( const KDateTime &completed )
00297 {
00298   update();
00299   if ( !d->recurTodo( this ) ) {
00300     d->mHasCompletedDate = true;
00301     d->mPercentComplete = 100;
00302     d->mCompleted = completed.toUtc();
00303     setFieldDirty( FieldCompleted );
00304   }
00305   updated();
00306 }
00307 
00308 bool Todo::hasCompletedDate() const
00309 {
00310   return d->mHasCompletedDate;
00311 }
00312 
00313 int Todo::percentComplete() const
00314 {
00315   return d->mPercentComplete;
00316 }
00317 
00318 void Todo::setPercentComplete( int percent )
00319 {
00320   if ( percent > 100 ) {
00321     percent = 100;
00322   } else if ( percent < 0 ) {
00323     percent = 0;
00324   }
00325 
00326   update();
00327   d->mPercentComplete = percent;
00328   if ( percent != 100 ) {
00329     d->mHasCompletedDate = false;
00330   }
00331   setFieldDirty( FieldPercentComplete );
00332   updated();
00333 }
00334 
00335 bool Todo::isInProgress( bool first ) const
00336 {
00337   if ( isOverdue() ) {
00338     return false;
00339   }
00340 
00341   if ( d->mPercentComplete > 0 ) {
00342     return true;
00343   }
00344 
00345   if ( d->mHasStartDate && d->mHasDueDate ) {
00346     if ( allDay() ) {
00347       QDate currDate = QDate::currentDate();
00348       if ( dtStart( first ).date() <= currDate && currDate < dtDue( first ).date() ) {
00349         return true;
00350       }
00351     } else {
00352       KDateTime currDate = KDateTime::currentUtcDateTime();
00353       if ( dtStart( first ) <= currDate && currDate < dtDue( first ) ) {
00354         return true;
00355       }
00356     }
00357   }
00358 
00359   return false;
00360 }
00361 
00362 bool Todo::isOpenEnded() const
00363 {
00364   if ( !d->mHasDueDate && !isCompleted() ) {
00365     return true;
00366   }
00367   return false;
00368 
00369 }
00370 
00371 bool Todo::isNotStarted( bool first ) const
00372 {
00373   if ( d->mPercentComplete > 0 ) {
00374     return false;
00375   }
00376 
00377   if ( !d->mHasStartDate ) {
00378     return false;
00379   }
00380 
00381   if ( allDay() ) {
00382     if ( dtStart( first ).date() >= QDate::currentDate() ) {
00383       return false;
00384     }
00385   } else {
00386     if ( dtStart( first ) >= KDateTime::currentUtcDateTime() ) {
00387       return false;
00388     }
00389   }
00390   return true;
00391 }
00392 
00393 void Todo::shiftTimes( const KDateTime::Spec &oldSpec,
00394                        const KDateTime::Spec &newSpec )
00395 {
00396   Incidence::shiftTimes( oldSpec, newSpec );
00397   d->mDtDue = d->mDtDue.toTimeSpec( oldSpec );
00398   d->mDtDue.setTimeSpec( newSpec );
00399   if ( recurs() ) {
00400     d->mDtRecurrence = d->mDtRecurrence.toTimeSpec( oldSpec );
00401     d->mDtRecurrence.setTimeSpec( newSpec );
00402   }
00403   if ( d->mHasCompletedDate ) {
00404     d->mCompleted = d->mCompleted.toTimeSpec( oldSpec );
00405     d->mCompleted.setTimeSpec( newSpec );
00406   }
00407 }
00408 
00409 void Todo::setDtRecurrence( const KDateTime &dt )
00410 {
00411   d->mDtRecurrence = dt;
00412   setFieldDirty( FieldRecurrence );
00413 }
00414 
00415 KDateTime Todo::dtRecurrence() const
00416 {
00417   return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
00418 }
00419 
00420 bool Todo::recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const
00421 {
00422   QDate today = QDate::currentDate();
00423   return
00424     Incidence::recursOn( date, timeSpec ) &&
00425     !( date < today && d->mDtRecurrence.date() < today &&
00426        d->mDtRecurrence > recurrence()->startDateTime() );
00427 }
00428 
00429 bool Todo::isOverdue() const
00430 {
00431   if ( !dtDue().isValid() ) {
00432     return false; // if it's never due, it can't be overdue
00433   }
00434 
00435   bool inPast = allDay() ?
00436                 dtDue().date() < QDate::currentDate() :
00437                 dtDue() < KDateTime::currentUtcDateTime();
00438   return inPast && !isCompleted();
00439 }
00440 
00441 void Todo::setAllDay( bool allday )
00442 {
00443   if ( allday != allDay() && !mReadOnly ) {
00444     if ( hasDueDate() && dtDue().isValid() ) {
00445       setFieldDirty( FieldDtDue );
00446     }
00447     Incidence::setAllDay( allday );
00448   }
00449 }
00450 
00451 //@cond PRIVATE
00452 bool Todo::Private::recurTodo( Todo *todo )
00453 {
00454   if ( todo && todo->recurs() ) {
00455     Recurrence *r = todo->recurrence();
00456     KDateTime endDateTime = r->endDateTime();
00457     KDateTime nextDate = r->getNextDateTime( todo->dtDue() );
00458 
00459     if ( ( r->duration() == -1 ||
00460            ( nextDate.isValid() && endDateTime.isValid() &&
00461              nextDate <= endDateTime ) ) ) {
00462 
00463       while ( !todo->recursAt( nextDate ) ||
00464               nextDate <= KDateTime::currentUtcDateTime() ) {
00465 
00466         if ( !nextDate.isValid() ||
00467              ( nextDate > endDateTime && r->duration() != -1 ) ) {
00468 
00469           return false;
00470         }
00471 
00472         nextDate = r->getNextDateTime( nextDate );
00473       }
00474 
00475       todo->setDtDue( nextDate );
00476       todo->setCompleted( false );
00477       todo->setRevision( todo->revision() + 1 );
00478 
00479       return true;
00480     }
00481   }
00482 
00483   return false;
00484 }
00485 //@endcond
00486 
00487 bool Todo::accept( Visitor &v, IncidenceBase::Ptr incidence )
00488 {
00489   return v.visit( incidence.staticCast<Todo>() );
00490 }
00491 
00492 KDateTime Todo::dateTime( DateTimeRole role ) const
00493 {
00494   switch ( role ) {
00495   case RoleAlarmStartOffset:
00496     return dtStart();
00497   case RoleAlarmEndOffset:
00498     return dtDue();
00499   case RoleSort:
00500     // Sorting to-dos first compares dtDue, then dtStart if
00501     // dtDue doesn't exist
00502     return hasDueDate() ? dtDue() : dtStart();
00503   case RoleCalendarHashing:
00504     return dtDue();
00505   case RoleStartTimeZone:
00506     return dtStart();
00507   case RoleEndTimeZone:
00508     return dtDue();
00509   case RoleEndRecurrenceBase:
00510     return dtDue();
00511   case RoleDisplayEnd:
00512     return dtDue();
00513   case RoleAlarm:
00514     if ( alarms().isEmpty() ) {
00515       return KDateTime();
00516     } else {
00517       Alarm::Ptr alarm = alarms().first();
00518       if ( alarm->hasStartOffset() && hasStartDate() ) {
00519         return dtStart();
00520       } else if ( alarm->hasEndOffset() && hasDueDate() ) {
00521         return dtDue();
00522       } else {
00523         // The application shouldn't add alarms on to-dos without dates.
00524         return KDateTime();
00525       }
00526     }
00527   case RoleRecurrenceStart:
00528     return dtDue();
00529     break;
00530   case RoleEnd:
00531     // todos don't have dtEnd
00532   default:
00533     return KDateTime();
00534   }
00535 }
00536 
00537 void Todo::setDateTime( const KDateTime &dateTime, DateTimeRole role )
00538 {
00539   Q_UNUSED( dateTime );
00540   Q_UNUSED( role );
00541 }
00542 
00543 void Todo::virtual_hook( int id, void *data )
00544 {
00545   Q_UNUSED( id );
00546   Q_UNUSED( data );
00547   Q_ASSERT( false );
00548 }
00549 
00550 QLatin1String Todo::mimeType() const
00551 {
00552   return Todo::todoMimeType();
00553 }
00554 
00555 QLatin1String Todo::todoMimeType()
00556 {
00557   return QLatin1String( "application/x-vnd.akonadi.calendar.todo" );
00558 }
00559 
00560 QLatin1String Todo::iconName( const KDateTime &recurrenceId ) const
00561 {
00562   KDateTime occurrenceDT = recurrenceId;
00563 
00564   if ( recurs() && occurrenceDT.isDateOnly() ) {
00565     occurrenceDT.setTime( QTime( 0, 0 ) );
00566   }
00567 
00568   const bool usesCompletedTaskPixmap = isCompleted() ||
00569                                        ( recurs() && occurrenceDT.isValid() &&
00570                                          occurrenceDT < dtDue( false ) );
00571 
00572   if ( usesCompletedTaskPixmap ) {
00573     return QLatin1String( "task-complete" );
00574   } else {
00575     return QLatin1String( "view-calendar-tasks" );
00576   }
00577 }

KCalCore Library

Skip menu "KCalCore 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.6.1
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