KCal Library
todo.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00032 #include "todo.h"
00033
00034 #include <kglobal.h>
00035 #include <klocale.h>
00036 #include <kdebug.h>
00037 #include <ksystemtimezone.h>
00038
00039 using namespace KCal;
00040
00045
00046 class KCal::Todo::Private
00047 {
00048 public:
00049 Private()
00050 : mPercentComplete( 0 ),
00051 mHasDueDate( false ),
00052 mHasStartDate( false ),
00053 mHasCompletedDate( false )
00054 {}
00055 Private( const KCal::Todo::Private &other )
00056 { init( other ); }
00057
00058 void init( const KCal::Todo::Private &other );
00059
00060 KDateTime mDtDue;
00061
00062 KDateTime mDtRecurrence;
00063 KDateTime mCompleted;
00064 int mPercentComplete;
00065 bool mHasDueDate;
00066 bool mHasStartDate;
00067 bool mHasCompletedDate;
00068
00072 bool recurTodo( Todo *todo );
00073 };
00074
00075 void KCal::Todo::Private::init( const KCal::Todo::Private &other )
00076 {
00077 mDtDue = other.mDtDue;
00078 mDtRecurrence = other.mDtRecurrence;
00079 mCompleted = other.mCompleted;
00080 mPercentComplete = other.mPercentComplete;
00081 mHasDueDate = other.mHasDueDate;
00082 mHasStartDate = other.mHasStartDate;
00083 mHasCompletedDate = other.mHasCompletedDate;
00084 }
00085
00086
00087
00088 Todo::Todo()
00089 : d( new KCal::Todo::Private )
00090 {
00091 }
00092
00093 Todo::Todo( const Todo &other )
00094 : Incidence( other ),
00095 d( new KCal::Todo::Private( *other.d ) )
00096 {
00097 }
00098
00099 Todo::~Todo()
00100 {
00101 delete d;
00102 }
00103
00104 Todo *Todo::clone()
00105 {
00106 return new Todo( *this );
00107 }
00108
00109 Todo &Todo::operator=( const Todo &other )
00110 {
00111 Incidence::operator=( other );
00112 d->init( *other.d );
00113 return *this;
00114 }
00115
00116 bool Todo::operator==( const Todo &todo ) const
00117 {
00118 return
00119 static_cast<const Incidence &>( *this ) == static_cast<const Incidence &>( todo ) &&
00120 dtDue() == todo.dtDue() &&
00121 hasDueDate() == todo.hasDueDate() &&
00122 hasStartDate() == todo.hasStartDate() &&
00123 completed() == todo.completed() &&
00124 hasCompletedDate() == todo.hasCompletedDate() &&
00125 percentComplete() == todo.percentComplete();
00126 }
00127
00128 QByteArray Todo::type() const
00129 {
00130 return "Todo";
00131 }
00132
00133 void Todo::setDtDue( const KDateTime &dtDue, bool first )
00134 {
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 if ( recurs() && !first ) {
00145 d->mDtRecurrence = dtDue;
00146 } else {
00147 d->mDtDue = dtDue;
00148
00149 recurrence()->setStartDateTime( dtDue );
00150 recurrence()->setAllDay( allDay() );
00151 }
00152
00153 if ( recurs() && dtDue < recurrence()->startDateTime() ) {
00154 setDtStart( dtDue );
00155 }
00156
00157
00158
00159
00160
00161
00162
00163 updated();
00164 }
00165
00166 KDateTime Todo::dtDue( bool first ) const
00167 {
00168 if ( !hasDueDate() ) {
00169 return KDateTime();
00170 }
00171 if ( recurs() && !first && d->mDtRecurrence.isValid() ) {
00172 return d->mDtRecurrence;
00173 }
00174
00175 return d->mDtDue;
00176 }
00177
00178 QString Todo::dtDueTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
00179 {
00180 if ( spec.isValid() ) {
00181
00182 QString timeZone;
00183 if ( spec.timeZone() != KSystemTimeZones::local() ) {
00184 timeZone = ' ' + spec.timeZone().name();
00185 }
00186
00187 return KGlobal::locale()->formatTime( dtDue( !recurs() ).toTimeSpec( spec ).time(), !shortfmt )
00188 + timeZone;
00189 } else {
00190 return KGlobal::locale()->formatTime( dtDue( !recurs() ).time(), !shortfmt );
00191 }
00192 }
00193
00194 QString Todo::dtDueDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
00195 {
00196 if ( spec.isValid() ) {
00197
00198 QString timeZone;
00199 if ( spec.timeZone() != KSystemTimeZones::local() ) {
00200 timeZone = ' ' + spec.timeZone().name();
00201 }
00202
00203 return KGlobal::locale()->formatDate(
00204 dtDue( !recurs() ).toTimeSpec( spec ).date(),
00205 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) )
00206 + timeZone;
00207 } else {
00208 return KGlobal::locale()->formatDate(
00209 dtDue( !recurs() ).date(),
00210 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00211 }
00212 }
00213
00214 QString Todo::dtDueStr( bool shortfmt, const KDateTime::Spec &spec ) const
00215 {
00216 if ( allDay() ) {
00217 return dtDueDateStr( shortfmt, spec );
00218 }
00219
00220 if ( spec.isValid() ) {
00221
00222 QString timeZone;
00223 if ( spec.timeZone() != KSystemTimeZones::local() ) {
00224 timeZone = ' ' + spec.timeZone().name();
00225 }
00226
00227 return KGlobal::locale()->formatDateTime(
00228 dtDue( !recurs() ).toTimeSpec( spec ).dateTime(),
00229 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) )
00230 + timeZone;
00231 } else {
00232 return KGlobal::locale()->formatDateTime(
00233 dtDue( !recurs() ).dateTime(),
00234 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00235 }
00236 }
00237
00238 bool Todo::hasDueDate() const
00239 {
00240 return d->mHasDueDate;
00241 }
00242
00243 void Todo::setHasDueDate( bool f )
00244 {
00245 if ( mReadOnly ) {
00246 return;
00247 }
00248 d->mHasDueDate = f;
00249 updated();
00250 }
00251
00252 bool Todo::hasStartDate() const
00253 {
00254 return d->mHasStartDate;
00255 }
00256
00257 void Todo::setHasStartDate( bool f )
00258 {
00259 if ( mReadOnly ) {
00260 return;
00261 }
00262
00263 if ( recurs() && !f ) {
00264 if ( !comments().filter( "NoStartDate" ).count() ) {
00265 addComment( "NoStartDate" );
00266 }
00267 } else {
00268 QString s( "NoStartDate" );
00269 removeComment( s );
00270 }
00271 d->mHasStartDate = f;
00272 updated();
00273 }
00274
00275 KDateTime Todo::dtStart() const
00276 {
00277 return dtStart( false );
00278 }
00279
00280 KDateTime Todo::dtStart( bool first ) const
00281 {
00282 if ( !hasStartDate() ) {
00283 return KDateTime();
00284 }
00285 if ( recurs() && !first ) {
00286 return d->mDtRecurrence.addDays( dtDue( first ).daysTo( IncidenceBase::dtStart() ) );
00287 } else {
00288 return IncidenceBase::dtStart();
00289 }
00290 }
00291
00292 void Todo::setDtStart( const KDateTime &dtStart )
00293 {
00294
00295 if ( recurs() ) {
00296 recurrence()->setStartDateTime( d->mDtDue );
00297 recurrence()->setAllDay( allDay() );
00298 }
00299 IncidenceBase::setDtStart( dtStart );
00300 }
00301
00302 QString Todo::dtStartTimeStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
00303 {
00304 if ( spec.isValid() ) {
00305
00306 QString timeZone;
00307 if ( spec.timeZone() != KSystemTimeZones::local() ) {
00308 timeZone = ' ' + spec.timeZone().name();
00309 }
00310
00311 return KGlobal::locale()->formatTime( dtStart( first ).toTimeSpec( spec ).time(), !shortfmt )
00312 + timeZone;
00313 } else {
00314 return KGlobal::locale()->formatTime( dtStart( first ).time(), !shortfmt );
00315 }
00316 }
00317
00318 QString Todo::dtStartTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
00319 {
00320 return Incidence::dtStartTimeStr( shortfmt, spec );
00321 }
00322
00323 QString Todo::dtStartDateStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
00324 {
00325 if ( spec.isValid() ) {
00326
00327 QString timeZone;
00328 if ( spec.timeZone() != KSystemTimeZones::local() ) {
00329 timeZone = ' ' + spec.timeZone().name();
00330 }
00331
00332 return
00333 KGlobal::locale()->formatDate( dtStart( first ).toTimeSpec( spec ).date(),
00334 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) )
00335 + timeZone;
00336 } else {
00337 return
00338 KGlobal::locale()->formatDate( dtStart( first ).date(),
00339 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00340 }
00341 }
00342
00343 QString Todo::dtStartDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
00344 {
00345 return Incidence::dtStartDateStr( shortfmt, spec );
00346 }
00347
00348 QString Todo::dtStartStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
00349 {
00350 if ( allDay() ) {
00351 return dtStartDateStr( shortfmt, spec );
00352 }
00353
00354 if ( spec.isValid() ) {
00355
00356 QString timeZone;
00357 if ( spec.timeZone() != KSystemTimeZones::local() ) {
00358 timeZone = ' ' + spec.timeZone().name();
00359 }
00360
00361 return
00362 KGlobal::locale()->formatDateTime( dtStart( first ).toTimeSpec( spec ).dateTime(),
00363 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) )
00364 + timeZone;
00365 } else {
00366 return
00367 KGlobal::locale()->formatDateTime( dtStart( first ).dateTime(),
00368 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00369 }
00370 }
00371
00372 QString Todo::dtStartStr( bool shortfmt, const KDateTime::Spec &spec ) const
00373 {
00374 return Incidence::dtStartStr( shortfmt, spec );
00375 }
00376
00377 bool Todo::isCompleted() const
00378 {
00379 if ( d->mPercentComplete == 100 ) {
00380 return true;
00381 } else {
00382 return false;
00383 }
00384 }
00385
00386 void Todo::setCompleted( bool completed )
00387 {
00388 if ( completed ) {
00389 d->mPercentComplete = 100;
00390 } else {
00391 d->mPercentComplete = 0;
00392 d->mHasCompletedDate = false;
00393 d->mCompleted = KDateTime();
00394 }
00395 updated();
00396 }
00397
00398 KDateTime Todo::completed() const
00399 {
00400 if ( hasCompletedDate() ) {
00401 return d->mCompleted;
00402 } else {
00403 return KDateTime();
00404 }
00405 }
00406
00407 QString Todo::completedStr( bool shortfmt ) const
00408 {
00409 return
00410 KGlobal::locale()->formatDateTime( d->mCompleted.dateTime(),
00411 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
00412 }
00413
00414 void Todo::setCompleted( const KDateTime &completed )
00415 {
00416 if ( !d->recurTodo( this ) ) {
00417 d->mHasCompletedDate = true;
00418 d->mPercentComplete = 100;
00419 d->mCompleted = completed.toUtc();
00420 }
00421 updated();
00422 }
00423
00424 bool Todo::hasCompletedDate() const
00425 {
00426 return d->mHasCompletedDate;
00427 }
00428
00429 int Todo::percentComplete() const
00430 {
00431 return d->mPercentComplete;
00432 }
00433
00434 void Todo::setPercentComplete( int percent )
00435 {
00436
00437 d->mPercentComplete = percent;
00438 if ( percent != 100 ) {
00439 d->mHasCompletedDate = false;
00440 }
00441 updated();
00442 }
00443
00444 void Todo::shiftTimes( const KDateTime::Spec &oldSpec,
00445 const KDateTime::Spec &newSpec )
00446 {
00447 Incidence::shiftTimes( oldSpec, newSpec );
00448 d->mDtDue = d->mDtDue.toTimeSpec( oldSpec );
00449 d->mDtDue.setTimeSpec( newSpec );
00450 if ( recurs() ) {
00451 d->mDtRecurrence = d->mDtRecurrence.toTimeSpec( oldSpec );
00452 d->mDtRecurrence.setTimeSpec( newSpec );
00453 }
00454 if ( d->mHasCompletedDate ) {
00455 d->mCompleted = d->mCompleted.toTimeSpec( oldSpec );
00456 d->mCompleted.setTimeSpec( newSpec );
00457 }
00458 }
00459
00460 void Todo::setDtRecurrence( const KDateTime &dt )
00461 {
00462 d->mDtRecurrence = dt;
00463 }
00464
00465 KDateTime Todo::dtRecurrence() const
00466 {
00467 return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
00468 }
00469
00470 bool Todo::recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const
00471 {
00472 QDate today = QDate::currentDate();
00473 return
00474 Incidence::recursOn( date, timeSpec ) &&
00475 !( date < today && d->mDtRecurrence.date() < today &&
00476 d->mDtRecurrence > recurrence()->startDateTime() );
00477 }
00478
00479 bool Todo::isOverdue() const
00480 {
00481 if ( !dtDue().isValid() ) {
00482 return false;
00483 }
00484
00485 bool inPast = allDay() ?
00486 dtDue().date() < QDate::currentDate() :
00487 dtDue() < KDateTime::currentUtcDateTime();
00488 return inPast && !isCompleted();
00489 }
00490
00491 KDateTime Todo::endDateRecurrenceBase() const
00492 {
00493 return dtDue();
00494 }
00495
00496
00497 bool Todo::Private::recurTodo( Todo *todo )
00498 {
00499 if ( todo->recurs() ) {
00500 Recurrence *r = todo->recurrence();
00501 KDateTime endDateTime = r->endDateTime();
00502 KDateTime nextDate = r->getNextDateTime( todo->dtDue() );
00503
00504 if ( ( r->duration() == -1 ||
00505 ( nextDate.isValid() && endDateTime.isValid() &&
00506 nextDate <= endDateTime ) ) ) {
00507
00508 while ( !todo->recursAt( nextDate ) ||
00509 nextDate <= KDateTime::currentUtcDateTime() ) {
00510
00511 if ( !nextDate.isValid() ||
00512 ( nextDate > endDateTime && r->duration() != -1 ) ) {
00513
00514 return false;
00515 }
00516
00517 nextDate = r->getNextDateTime( nextDate );
00518 }
00519
00520 todo->setDtDue( nextDate );
00521 todo->setCompleted( false );
00522 todo->setRevision( todo->revision() + 1 );
00523
00524 return true;
00525 }
00526 }
00527
00528 return false;
00529 }
00530