• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • 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   d->mHasDueDate = dtDue.isValid();
00158 
00159   if ( recurs() && !first ) {
00160     d->mDtRecurrence = dtDue;
00161   } else {
00162     d->mDtDue = dtDue;
00163     // TODO: This doesn't seem right...
00164     recurrence()->setStartDateTime( dtDue );
00165     recurrence()->setAllDay( allDay() );
00166   }
00167 
00168   if ( recurs() && dtDue < recurrence()->startDateTime() ) {
00169     setDtStart( dtDue );
00170   }
00171 
00172   /*const Alarm::List& alarms = alarms();
00173   for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next())
00174     alarm->setAlarmStart(d->mDtDue);*/
00175   setFieldDirty( FieldDtDue );
00176   endUpdates();
00177 }
00178 
00179 KDateTime Todo::dtDue( bool first ) const
00180 {
00181   if ( !hasDueDate() ) {
00182     return KDateTime();
00183   }
00184   if ( recurs() && !first && d->mDtRecurrence.isValid() ) {
00185     return d->mDtRecurrence;
00186   }
00187 
00188   return d->mDtDue;
00189 }
00190 
00191 bool Todo::hasDueDate() const
00192 {
00193   return d->mHasDueDate;
00194 }
00195 
00196 void Todo::setHasDueDate( bool f )
00197 {
00198   if ( mReadOnly ) {
00199     return;
00200   }
00201   update();
00202   d->mHasDueDate = f;
00203   setFieldDirty( FieldDtDue );
00204   updated();
00205 }
00206 
00207 bool Todo::hasStartDate() const
00208 {
00209   return d->mHasStartDate;
00210 }
00211 
00212 void Todo::setHasStartDate( bool f )
00213 {
00214   if ( mReadOnly ) {
00215     return;
00216   }
00217 
00218   update();
00219   if ( recurs() && !f ) {
00220     if ( !comments().filter( "NoStartDate" ).count() ) {
00221       addComment( "NoStartDate" ); //TODO: --> custom flag?
00222     }
00223   } else {
00224     QString s( "NoStartDate" );
00225     removeComment( s );
00226   }
00227   d->mHasStartDate = f;
00228   setFieldDirty( FieldDtStart );
00229   updated();
00230 }
00231 
00232 KDateTime Todo::dtStart() const
00233 {
00234   return dtStart( false );
00235 }
00236 
00237 KDateTime Todo::dtStart( bool first ) const
00238 {
00239   if ( !hasStartDate() ) {
00240     return KDateTime();
00241   }
00242   if ( recurs() && !first ) {
00243     KDateTime dt = d->mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
00244     dt.setTime( IncidenceBase::dtStart().time() );
00245     return dt;
00246   } else {
00247     return IncidenceBase::dtStart();
00248   }
00249 }
00250 
00251 void Todo::setDtStart( const KDateTime &dtStart )
00252 {
00253   // TODO: This doesn't seem right (rfc 2445/6 says, recurrence is calculated from the dtstart...)
00254 
00255   d->mHasStartDate = dtStart.isValid();
00256 
00257   if ( recurs() ) {
00258     recurrence()->setStartDateTime( d->mDtDue );
00259     recurrence()->setAllDay( allDay() );
00260   }
00261   IncidenceBase::setDtStart( dtStart );
00262 }
00263 
00264 bool Todo::isCompleted() const
00265 {
00266   return d->mPercentComplete == 100;
00267 }
00268 
00269 void Todo::setCompleted( bool completed )
00270 {
00271   update();
00272   if ( completed ) {
00273     d->mPercentComplete = 100;
00274   } else {
00275     d->mPercentComplete = 0;
00276     d->mHasCompletedDate = false;
00277     d->mCompleted = KDateTime();
00278   }
00279   setFieldDirty( FieldCompleted );
00280   updated();
00281 }
00282 
00283 KDateTime Todo::completed() const
00284 {
00285   if ( hasCompletedDate() ) {
00286     return d->mCompleted;
00287   } else {
00288     return KDateTime();
00289   }
00290 }
00291 
00292 void Todo::setCompleted( const KDateTime &completed )
00293 {
00294   update();
00295   if ( !d->recurTodo( this ) ) {
00296     d->mHasCompletedDate = true;
00297     d->mPercentComplete = 100;
00298     d->mCompleted = completed.toUtc();
00299     setFieldDirty( FieldCompleted );
00300   }
00301   updated();
00302 }
00303 
00304 bool Todo::hasCompletedDate() const
00305 {
00306   return d->mHasCompletedDate;
00307 }
00308 
00309 int Todo::percentComplete() const
00310 {
00311   return d->mPercentComplete;
00312 }
00313 
00314 void Todo::setPercentComplete( int percent )
00315 {
00316   if ( percent > 100 ) {
00317     percent = 100;
00318   } else if ( percent < 0 ) {
00319     percent = 0;
00320   }
00321 
00322   update();
00323   d->mPercentComplete = percent;
00324   if ( percent != 100 ) {
00325     d->mHasCompletedDate = false;
00326   }
00327   setFieldDirty( FieldPercentComplete );
00328   updated();
00329 }
00330 
00331 bool Todo::isInProgress( bool first ) const
00332 {
00333   if ( isOverdue() ) {
00334     return false;
00335   }
00336 
00337   if ( d->mPercentComplete > 0 ) {
00338     return true;
00339   }
00340 
00341   if ( d->mHasStartDate && d->mHasDueDate ) {
00342     if ( allDay() ) {
00343       QDate currDate = QDate::currentDate();
00344       if ( dtStart( first ).date() <= currDate && currDate < dtDue( first ).date() ) {
00345         return true;
00346       }
00347     } else {
00348       KDateTime currDate = KDateTime::currentUtcDateTime();
00349       if ( dtStart( first ) <= currDate && currDate < dtDue( first ) ) {
00350         return true;
00351       }
00352     }
00353   }
00354 
00355   return false;
00356 }
00357 
00358 bool Todo::isOpenEnded() const
00359 {
00360   if ( !d->mHasDueDate && !isCompleted() ) {
00361     return true;
00362   }
00363   return false;
00364 
00365 }
00366 
00367 bool Todo::isNotStarted( bool first ) const
00368 {
00369   if ( d->mPercentComplete > 0 ) {
00370     return false;
00371   }
00372 
00373   if ( !d->mHasStartDate ) {
00374     return false;
00375   }
00376 
00377   if ( allDay() ) {
00378     if ( dtStart( first ).date() >= QDate::currentDate() ) {
00379       return false;
00380     }
00381   } else {
00382     if ( dtStart( first ) >= KDateTime::currentUtcDateTime() ) {
00383       return false;
00384     }
00385   }
00386   return true;
00387 }
00388 
00389 void Todo::shiftTimes( const KDateTime::Spec &oldSpec,
00390                        const KDateTime::Spec &newSpec )
00391 {
00392   Incidence::shiftTimes( oldSpec, newSpec );
00393   d->mDtDue = d->mDtDue.toTimeSpec( oldSpec );
00394   d->mDtDue.setTimeSpec( newSpec );
00395   if ( recurs() ) {
00396     d->mDtRecurrence = d->mDtRecurrence.toTimeSpec( oldSpec );
00397     d->mDtRecurrence.setTimeSpec( newSpec );
00398   }
00399   if ( d->mHasCompletedDate ) {
00400     d->mCompleted = d->mCompleted.toTimeSpec( oldSpec );
00401     d->mCompleted.setTimeSpec( newSpec );
00402   }
00403 }
00404 
00405 void Todo::setDtRecurrence( const KDateTime &dt )
00406 {
00407   d->mDtRecurrence = dt;
00408   setFieldDirty( FieldRecurrence );
00409 }
00410 
00411 KDateTime Todo::dtRecurrence() const
00412 {
00413   return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
00414 }
00415 
00416 bool Todo::recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const
00417 {
00418   QDate today = QDate::currentDate();
00419   return
00420     Incidence::recursOn( date, timeSpec ) &&
00421     !( date < today && d->mDtRecurrence.date() < today &&
00422        d->mDtRecurrence > recurrence()->startDateTime() );
00423 }
00424 
00425 bool Todo::isOverdue() const
00426 {
00427   if ( !dtDue().isValid() ) {
00428     return false; // if it's never due, it can't be overdue
00429   }
00430 
00431   const bool inPast = allDay() ?
00432                       dtDue().date() < QDate::currentDate() :
00433                       dtDue() < KDateTime::currentUtcDateTime();
00434   return inPast && !isCompleted();
00435 }
00436 
00437 void Todo::setAllDay( bool allday )
00438 {
00439   if ( allday != allDay() && !mReadOnly ) {
00440     if ( hasDueDate() && dtDue().isValid() ) {
00441       setFieldDirty( FieldDtDue );
00442     }
00443     Incidence::setAllDay( allday );
00444   }
00445 }
00446 
00447 //@cond PRIVATE
00448 bool Todo::Private::recurTodo( Todo *todo )
00449 {
00450   if ( todo && todo->recurs() ) {
00451     Recurrence *r = todo->recurrence();
00452     const KDateTime recurrenceEndDateTime = r->endDateTime();
00453     KDateTime nextOccurrenceDateTime = r->getNextDateTime( todo->dtDue() );
00454 
00455     if ( ( r->duration() == -1 ||
00456            ( nextOccurrenceDateTime.isValid() && recurrenceEndDateTime.isValid() &&
00457              nextOccurrenceDateTime <= recurrenceEndDateTime ) ) ) {
00458       // We convert to the same timeSpec so we get the correct .date()
00459       const KDateTime rightNow =
00460         KDateTime::currentUtcDateTime().toTimeSpec( nextOccurrenceDateTime.timeSpec() );
00461       const bool isDateOnly = todo->allDay();
00462 
00463       /* Now we search for the occurrence that's _after_ the currentUtcDateTime, or
00464        * if it's dateOnly, the occurrrence that's _during or after today_.
00465        * The reason we use "<" for date only, but "<=" for ocurrences with time is that
00466        * if it's date only, the user can still complete that ocurrence today, so that's
00467        * the current ocurrence that needs completing.
00468        */
00469       while ( !todo->recursAt( nextOccurrenceDateTime )                ||
00470               ( !isDateOnly && nextOccurrenceDateTime <= rightNow )    ||
00471               ( isDateOnly && nextOccurrenceDateTime.date() < rightNow.date() ) ) {
00472 
00473         if ( !nextOccurrenceDateTime.isValid() ||
00474              ( nextOccurrenceDateTime > recurrenceEndDateTime && r->duration() != -1 ) ) {
00475           return false;
00476         }
00477         nextOccurrenceDateTime = r->getNextDateTime( nextOccurrenceDateTime );
00478       }
00479 
00480       todo->setDtDue( nextOccurrenceDateTime );
00481       todo->setCompleted( false );
00482       todo->setRevision( todo->revision() + 1 );
00483 
00484       return true;
00485     }
00486   }
00487 
00488   return false;
00489 }
00490 //@endcond
00491 
00492 bool Todo::accept( Visitor &v, IncidenceBase::Ptr incidence )
00493 {
00494   return v.visit( incidence.staticCast<Todo>() );
00495 }
00496 
00497 KDateTime Todo::dateTime( DateTimeRole role ) const
00498 {
00499   switch ( role ) {
00500   case RoleAlarmStartOffset:
00501     return dtStart();
00502   case RoleAlarmEndOffset:
00503     return dtDue();
00504   case RoleSort:
00505     // Sorting to-dos first compares dtDue, then dtStart if
00506     // dtDue doesn't exist
00507     return hasDueDate() ? dtDue() : dtStart();
00508   case RoleCalendarHashing:
00509     return dtDue();
00510   case RoleStartTimeZone:
00511     return dtStart();
00512   case RoleEndTimeZone:
00513     return dtDue();
00514   case RoleEndRecurrenceBase:
00515     return dtDue();
00516   case RoleDisplayStart:
00517   case RoleDisplayEnd:
00518     return dtDue();
00519   case RoleAlarm:
00520     if ( alarms().isEmpty() ) {
00521       return KDateTime();
00522     } else {
00523       Alarm::Ptr alarm = alarms().first();
00524       if ( alarm->hasStartOffset() && hasStartDate() ) {
00525         return dtStart();
00526       } else if ( alarm->hasEndOffset() && hasDueDate() ) {
00527         return dtDue();
00528       } else {
00529         // The application shouldn't add alarms on to-dos without dates.
00530         return KDateTime();
00531       }
00532     }
00533   case RoleRecurrenceStart:
00534     return dtDue();
00535     break;
00536   case RoleEnd:
00537     // todos don't have dtEnd
00538   default:
00539     return KDateTime();
00540   }
00541 }
00542 
00543 void Todo::setDateTime( const KDateTime &dateTime, DateTimeRole role )
00544 {
00545   Q_UNUSED( dateTime );
00546   Q_UNUSED( role );
00547 }
00548 
00549 void Todo::virtual_hook( int id, void *data )
00550 {
00551   Q_UNUSED( id );
00552   Q_UNUSED( data );
00553   Q_ASSERT( false );
00554 }
00555 
00556 QLatin1String Todo::mimeType() const
00557 {
00558   return Todo::todoMimeType();
00559 }
00560 
00561 QLatin1String Todo::todoMimeType()
00562 {
00563   return QLatin1String( "application/x-vnd.akonadi.calendar.todo" );
00564 }
00565 
00566 QLatin1String Todo::iconName( const KDateTime &recurrenceId ) const
00567 {
00568   KDateTime occurrenceDT = recurrenceId;
00569 
00570   if ( recurs() && occurrenceDT.isDateOnly() ) {
00571     occurrenceDT.setTime( QTime( 0, 0 ) );
00572   }
00573 
00574   const bool usesCompletedTaskPixmap = isCompleted() ||
00575                                        ( recurs() && occurrenceDT.isValid() &&
00576                                          occurrenceDT < dtDue( false ) );
00577 
00578   if ( usesCompletedTaskPixmap ) {
00579     return QLatin1String( "task-complete" );
00580   } else {
00581     return QLatin1String( "view-calendar-tasks" );
00582   }
00583 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:48:21 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCalCore Library

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

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal