• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

KCal Library

  • kcal
todo.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcal library.
3 
4  Copyright (c) 2001-2003 Cornelius Schumacher <schumacher@kde.org>
5  Copyright (C) 2009 Allen Winter <winter@kde.org>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
34 #include "todo.h"
35 #include "incidenceformatter.h"
36 
37 #include <kglobal.h>
38 #include <klocale.h>
39 #include <kdebug.h>
40 #include <ksystemtimezone.h>
41 
42 using namespace KCal;
43 
48 //@cond PRIVATE
49 class KCal::Todo::Private
50 {
51  public:
52  Private()
53  : mPercentComplete( 0 ),
54  mHasDueDate( false ),
55  mHasStartDate( false ),
56  mHasCompletedDate( false )
57  {}
58  Private( const KCal::Todo::Private &other )
59  { init( other ); }
60 
61  void init( const KCal::Todo::Private &other );
62 
63  KDateTime mDtDue; // to-do due date (if there is one)
64  // ALSO the first occurrence of a recurring to-do
65  KDateTime mDtRecurrence; // next occurrence (for recurring to-dos)
66  KDateTime mCompleted; // to-do completion date (if it has been completed)
67  int mPercentComplete; // to-do percent complete [0,100]
68  bool mHasDueDate; // true if the to-do has a due date
69  bool mHasStartDate; // true if the to-do has a starting date
70  bool mHasCompletedDate; // true if the to-do has a completion date
71 
75  bool recurTodo( Todo *todo );
76 };
77 
78 void KCal::Todo::Private::init( const KCal::Todo::Private &other )
79 {
80  mDtDue = other.mDtDue;
81  mDtRecurrence = other.mDtRecurrence;
82  mCompleted = other.mCompleted;
83  mPercentComplete = other.mPercentComplete;
84  mHasDueDate = other.mHasDueDate;
85  mHasStartDate = other.mHasStartDate;
86  mHasCompletedDate = other.mHasCompletedDate;
87 }
88 
89 //@endcond
90 
91 Todo::Todo()
92  : d( new KCal::Todo::Private )
93 {
94 }
95 
96 Todo::Todo( const Todo &other )
97  : Incidence( other ),
98  d( new KCal::Todo::Private( *other.d ) )
99 {
100 }
101 
102 Todo::~Todo()
103 {
104  delete d;
105 }
106 
107 Todo *Todo::clone()
108 {
109  return new Todo( *this );
110 }
111 
112 Todo &Todo::operator=( const Todo &other )
113 {
114  // check for self assignment
115  if ( &other == this ) {
116  return *this;
117  }
118 
119  Incidence::operator=( other );
120  d->init( *other.d );
121  return *this;
122 }
123 
124 bool Todo::operator==( const Todo &todo ) const
125 {
126  return
127  Incidence::operator==( todo ) &&
128  dtDue() == todo.dtDue() &&
129  hasDueDate() == todo.hasDueDate() &&
130  hasStartDate() == todo.hasStartDate() &&
131  completed() == todo.completed() &&
132  hasCompletedDate() == todo.hasCompletedDate() &&
133  percentComplete() == todo.percentComplete();
134 }
135 
136 QByteArray Todo::type() const
137 {
138  return "Todo";
139 }
140 
141 //KDE5:
142 //QString Todo::typeStr() const
143 //{
144 // return i18nc( "incidence type is to-do/task", "to-do" );
145 //}
146 
147 void Todo::setDtDue( const KDateTime &dtDue, bool first )
148 {
149  //int diffsecs = d->mDtDue.secsTo(dtDue);
150 
151  /*if (mReadOnly) return;
152  const Alarm::List& alarms = alarms();
153  for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) {
154  if (alarm->enabled()) {
155  alarm->setTime(alarm->time().addSecs(diffsecs));
156  }
157  }*/
158 
159  d->mHasDueDate = true;
160  if ( recurs() && !first ) {
161  d->mDtRecurrence = dtDue;
162  } else {
163  d->mDtDue = dtDue;
164  // TODO: This doesn't seem right...
165  recurrence()->setStartDateTime( dtDue );
166  recurrence()->setAllDay( allDay() );
167  }
168 
169  if ( recurs() && dtDue < recurrence()->startDateTime() ) {
170  setDtStart( dtDue );
171  }
172 
173  /*const Alarm::List& alarms = alarms();
174  for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next())
175  alarm->setAlarmStart(d->mDtDue);*/
176 
177  updated();
178 }
179 
180 KDateTime Todo::dtDue( bool first ) const
181 {
182  if ( !hasDueDate() ) {
183  return KDateTime();
184  }
185  if ( recurs() && !first && d->mDtRecurrence.isValid() ) {
186  return d->mDtRecurrence;
187  }
188 
189  return d->mDtDue;
190 }
191 
192 QString Todo::dtDueTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
193 {
194  if ( spec.isValid() ) {
195 
196  QString timeZone;
197  if ( spec.timeZone() != KSystemTimeZones::local() ) {
198  timeZone = ' ' + spec.timeZone().name();
199  }
200 
201  return KGlobal::locale()->formatTime(
202  dtDue( !recurs() ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
203  } else {
204  return KGlobal::locale()->formatTime(
205  dtDue( !recurs() ).time(), !shortfmt );
206  }
207 }
208 
209 QString Todo::dtDueDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
210 {
211  if ( spec.isValid() ) {
212 
213  QString timeZone;
214  if ( spec.timeZone() != KSystemTimeZones::local() ) {
215  timeZone = ' ' + spec.timeZone().name();
216  }
217 
218  return KGlobal::locale()->formatDate(
219  dtDue( !recurs() ).toTimeSpec( spec ).date(),
220  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
221  } else {
222  return KGlobal::locale()->formatDate(
223  dtDue( !recurs() ).date(),
224  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
225  }
226 }
227 
228 QString Todo::dtDueStr( bool shortfmt, const KDateTime::Spec &spec ) const
229 {
230  if ( allDay() ) {
231  return IncidenceFormatter::dateToString( dtDue(), shortfmt, spec );
232  }
233 
234  if ( spec.isValid() ) {
235 
236  QString timeZone;
237  if ( spec.timeZone() != KSystemTimeZones::local() ) {
238  timeZone = ' ' + spec.timeZone().name();
239  }
240 
241  return KGlobal::locale()->formatDateTime(
242  dtDue( !recurs() ).toTimeSpec( spec ).dateTime(),
243  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
244  } else {
245  return KGlobal::locale()->formatDateTime(
246  dtDue( !recurs() ).dateTime(),
247  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
248  }
249 }
250 
251 bool Todo::hasDueDate() const
252 {
253  return d->mHasDueDate;
254 }
255 
256 void Todo::setHasDueDate( bool f )
257 {
258  if ( mReadOnly ) {
259  return;
260  }
261  d->mHasDueDate = f;
262  updated();
263 }
264 
265 bool Todo::hasStartDate() const
266 {
267  return d->mHasStartDate;
268 }
269 
270 void Todo::setHasStartDate( bool f )
271 {
272  if ( mReadOnly ) {
273  return;
274  }
275 
276  if ( recurs() && !f ) {
277  if ( !comments().filter( "NoStartDate" ).count() ) {
278  addComment( "NoStartDate" ); //TODO: --> custom flag?
279  }
280  } else {
281  QString s( "NoStartDate" );
282  removeComment( s );
283  }
284  d->mHasStartDate = f;
285  updated();
286 }
287 
288 KDateTime Todo::dtStart() const
289 {
290  return dtStart( false );
291 }
292 
293 KDateTime Todo::dtStart( bool first ) const
294 {
295  if ( !hasStartDate() ) {
296  return KDateTime();
297  }
298  if ( recurs() && !first ) {
299  KDateTime dt = d->mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
300  dt.setTime( IncidenceBase::dtStart().time() );
301  return dt;
302  } else {
303  return IncidenceBase::dtStart();
304  }
305 }
306 
307 void Todo::setDtStart( const KDateTime &dtStart )
308 {
309  // TODO: This doesn't seem right (rfc 2445/6 says, recurrence is calculated from the dtstart...)
310  if ( recurs() ) {
311  recurrence()->setStartDateTime( d->mDtDue );
312  recurrence()->setAllDay( allDay() );
313  }
314  d->mHasStartDate = true;
315  IncidenceBase::setDtStart( dtStart );
316 }
317 
318 QString Todo::dtStartTimeStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
319 {
320  if ( spec.isValid() ) {
321 
322  QString timeZone;
323  if ( spec.timeZone() != KSystemTimeZones::local() ) {
324  timeZone = ' ' + spec.timeZone().name();
325  }
326 
327  return KGlobal::locale()->formatTime(
328  dtStart( first ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
329  } else {
330  return KGlobal::locale()->formatTime(
331  dtStart( first ).time(), !shortfmt );
332  }
333 }
334 
335 QString Todo::dtStartTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
336 {
337  return IncidenceFormatter::timeToString( dtStart(), shortfmt, spec );
338 }
339 
340 QString Todo::dtStartDateStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
341 {
342  if ( spec.isValid() ) {
343 
344  QString timeZone;
345  if ( spec.timeZone() != KSystemTimeZones::local() ) {
346  timeZone = ' ' + spec.timeZone().name();
347  }
348 
349  return KGlobal::locale()->formatDate(
350  dtStart( first ).toTimeSpec( spec ).date(),
351  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
352  } else {
353  return KGlobal::locale()->formatDate(
354  dtStart( first ).date(),
355  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
356  }
357 }
358 
359 QString Todo::dtStartDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
360 {
361  return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec );
362 }
363 
364 QString Todo::dtStartStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const
365 {
366  if ( allDay() ) {
367  return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec );
368  }
369 
370  if ( spec.isValid() ) {
371 
372  QString timeZone;
373  if ( spec.timeZone() != KSystemTimeZones::local() ) {
374  timeZone = ' ' + spec.timeZone().name();
375  }
376 
377  return KGlobal::locale()->formatDateTime(
378  dtStart( first ).toTimeSpec( spec ).dateTime(),
379  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
380  } else {
381  return KGlobal::locale()->formatDateTime(
382  dtStart( first ).dateTime(),
383  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
384  }
385 }
386 
387 QString Todo::dtStartStr( bool shortfmt, const KDateTime::Spec &spec ) const
388 {
389  if ( allDay() ) {
390  return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec );
391  }
392 
393  if ( spec.isValid() ) {
394 
395  QString timeZone;
396  if ( spec.timeZone() != KSystemTimeZones::local() ) {
397  timeZone = ' ' + spec.timeZone().name();
398  }
399 
400  return KGlobal::locale()->formatDateTime(
401  dtStart().toTimeSpec( spec ).dateTime(),
402  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
403  } else {
404  return KGlobal::locale()->formatDateTime(
405  dtStart().dateTime(),
406  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
407  }
408 }
409 
410 bool Todo::isCompleted() const
411 {
412  if ( d->mPercentComplete == 100 ) {
413  return true;
414  } else {
415  return false;
416  }
417 }
418 
419 void Todo::setCompleted( bool completed )
420 {
421  if ( completed ) {
422  d->mPercentComplete = 100;
423  } else {
424  d->mPercentComplete = 0;
425  d->mHasCompletedDate = false;
426  d->mCompleted = KDateTime();
427  }
428  updated();
429 }
430 
431 KDateTime Todo::completed() const
432 {
433  if ( hasCompletedDate() ) {
434  return d->mCompleted;
435  } else {
436  return KDateTime();
437  }
438 }
439 
440 QString Todo::completedStr( bool shortfmt ) const
441 {
442  return
443  KGlobal::locale()->formatDateTime( d->mCompleted.dateTime(),
444  ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
445 }
446 
447 void Todo::setCompleted( const KDateTime &completed )
448 {
449  if ( !d->recurTodo( this ) ) {
450  d->mHasCompletedDate = true;
451  d->mPercentComplete = 100;
452  d->mCompleted = completed.toUtc();
453  }
454  updated();
455 }
456 
457 bool Todo::hasCompletedDate() const
458 {
459  return d->mHasCompletedDate;
460 }
461 
462 int Todo::percentComplete() const
463 {
464  return d->mPercentComplete;
465 }
466 
467 void Todo::setPercentComplete( int percent )
468 {
469  //TODO: (?) assert percent between 0 and 100, inclusive
470  d->mPercentComplete = percent;
471  if ( percent != 100 ) {
472  d->mHasCompletedDate = false;
473  }
474  updated();
475 }
476 
477 bool Todo::isInProgress( bool first ) const
478 {
479  if ( isOverdue() ) {
480  return false;
481  }
482 
483  if ( d->mPercentComplete > 0 ) {
484  return true;
485  }
486 
487  if ( d->mHasStartDate && d->mHasDueDate ) {
488  if ( allDay() ) {
489  QDate currDate = QDate::currentDate();
490  if ( dtStart( first ).date() <= currDate && currDate < dtDue( first ).date() ) {
491  return true;
492  }
493  } else {
494  KDateTime currDate = KDateTime::currentUtcDateTime();
495  if ( dtStart( first ) <= currDate && currDate < dtDue( first ) ) {
496  return true;
497  }
498  }
499  }
500 
501  return false;
502 }
503 
504 bool Todo::isOpenEnded() const
505 {
506  if ( !d->mHasDueDate && !isCompleted() ) {
507  return true;
508  }
509  return false;
510 
511 }
512 
513 bool Todo::isNotStarted( bool first ) const
514 {
515  if ( d->mPercentComplete > 0 ) {
516  return false;
517  }
518 
519  if ( !d->mHasStartDate ) {
520  return false;
521  }
522 
523  if ( allDay() ) {
524  if ( dtStart( first ).date() >= QDate::currentDate() ) {
525  return false;
526  }
527  } else {
528  if ( dtStart( first ) >= KDateTime::currentUtcDateTime() ) {
529  return false;
530  }
531  }
532  return true;
533 }
534 
535 void Todo::shiftTimes( const KDateTime::Spec &oldSpec,
536  const KDateTime::Spec &newSpec )
537 {
538  Incidence::shiftTimes( oldSpec, newSpec );
539  d->mDtDue = d->mDtDue.toTimeSpec( oldSpec );
540  d->mDtDue.setTimeSpec( newSpec );
541  if ( recurs() ) {
542  d->mDtRecurrence = d->mDtRecurrence.toTimeSpec( oldSpec );
543  d->mDtRecurrence.setTimeSpec( newSpec );
544  }
545  if ( d->mHasCompletedDate ) {
546  d->mCompleted = d->mCompleted.toTimeSpec( oldSpec );
547  d->mCompleted.setTimeSpec( newSpec );
548  }
549 }
550 
551 void Todo::setDtRecurrence( const KDateTime &dt )
552 {
553  d->mDtRecurrence = dt;
554 }
555 
556 KDateTime Todo::dtRecurrence() const
557 {
558  return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
559 }
560 
561 bool Todo::recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const
562 {
563  QDate today = QDate::currentDate();
564  return
565  Incidence::recursOn( date, timeSpec ) &&
566  !( date < today && d->mDtRecurrence.date() < today &&
567  d->mDtRecurrence > recurrence()->startDateTime() );
568 }
569 
570 bool Todo::isOverdue() const
571 {
572  if ( !dtDue().isValid() ) {
573  return false; // if it's never due, it can't be overdue
574  }
575 
576  bool inPast = allDay() ?
577  dtDue().date() < QDate::currentDate() :
578  dtDue() < KDateTime::currentUtcDateTime();
579  return inPast && !isCompleted();
580 }
581 
582 KDateTime Todo::endDateRecurrenceBase() const
583 {
584  return dtDue();
585 }
586 
587 //@cond PRIVATE
588 bool Todo::Private::recurTodo( Todo *todo )
589 {
590  if ( todo->recurs() ) {
591  Recurrence *r = todo->recurrence();
592  KDateTime endDateTime = r->endDateTime();
593  KDateTime nextDate = r->getNextDateTime( todo->dtDue() );
594 
595  if ( ( r->duration() == -1 ||
596  ( nextDate.isValid() && endDateTime.isValid() &&
597  nextDate <= endDateTime ) ) ) {
598 
599  while ( !todo->recursAt( nextDate ) ||
600  nextDate <= KDateTime::currentUtcDateTime() ) {
601 
602  if ( !nextDate.isValid() ||
603  ( nextDate > endDateTime && r->duration() != -1 ) ) {
604 
605  return false;
606  }
607 
608  nextDate = r->getNextDateTime( nextDate );
609  }
610 
611  todo->setDtDue( nextDate );
612  todo->setCompleted( false );
613  todo->setRevision( todo->revision() + 1 );
614 
615  return true;
616  }
617  }
618 
619  return false;
620 }
621 //@endcond
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:29:17 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCal Library

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

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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