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

KCalCore Library

  • kcalcore
todo.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalcore 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 "visitor.h"
36 
37 #include <KDebug>
38 
39 #include <QTime>
40 
41 using namespace KCalCore;
42 
47 //@cond PRIVATE
48 class KCalCore::Todo::Private
49 {
50 public:
51  Private()
52  : mPercentComplete(0)
53  {}
54  Private(const KCalCore::Todo::Private &other)
55  {
56  init(other);
57  }
58 
59  void init(const KCalCore::Todo::Private &other);
60 
61  KDateTime mDtDue; // to-do due date (if there is one)
62  // ALSO the first occurrence of a recurring to-do
63  KDateTime mDtRecurrence; // next occurrence (for recurring to-dos)
64  KDateTime mCompleted; // to-do completion date (if it has been completed)
65  int mPercentComplete; // to-do percent complete [0,100]
66 
70  bool recurTodo(Todo *todo);
71 };
72 
73 void KCalCore::Todo::Private::init(const KCalCore::Todo::Private &other)
74 {
75  mDtDue = other.mDtDue;
76  mDtRecurrence = other.mDtRecurrence;
77  mCompleted = other.mCompleted;
78  mPercentComplete = other.mPercentComplete;
79 }
80 
81 //@endcond
82 
83 Todo::Todo()
84  : d(new KCalCore::Todo::Private)
85 {
86 }
87 
88 Todo::Todo(const Todo &other)
89  : Incidence(other),
90  d(new KCalCore::Todo::Private(*other.d))
91 {
92 }
93 
94 Todo::~Todo()
95 {
96  delete d;
97 }
98 
99 Todo *Todo::clone() const
100 {
101  return new Todo(*this);
102 }
103 
104 IncidenceBase &Todo::assign(const IncidenceBase &other)
105 {
106  if (&other != this) {
107  Incidence::assign(other);
108  const Todo *t = static_cast<const Todo*>(&other);
109  d->init(*(t->d));
110  }
111  return *this;
112 }
113 
114 bool Todo::equals(const IncidenceBase &todo) const
115 {
116  if (!Incidence::equals(todo)) {
117  return false;
118  } else {
119  // If they weren't the same type IncidenceBase::equals would had returned false already
120  const Todo *t = static_cast<const Todo*>(&todo);
121  return ((dtDue() == t->dtDue()) ||
122  (!dtDue().isValid() && !t->dtDue().isValid())) &&
123  hasDueDate() == t->hasDueDate() &&
124  hasStartDate() == t->hasStartDate() &&
125  ((completed() == t->completed()) ||
126  (!completed().isValid() && !t->completed().isValid())) &&
127  hasCompletedDate() == t->hasCompletedDate() &&
128  percentComplete() == t->percentComplete();
129  }
130 }
131 
132 Incidence::IncidenceType Todo::type() const
133 {
134  return TypeTodo;
135 }
136 
137 QByteArray Todo::typeStr() const
138 {
139  return "Todo";
140 }
141 void Todo::setDtDue(const KDateTime &dtDue, bool first)
142 {
143  startUpdates();
144 
145  //int diffsecs = d->mDtDue.secsTo(dtDue);
146 
147  /*if (mReadOnly) return;
148  const Alarm::List& alarms = alarms();
149  for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) {
150  if (alarm->enabled()) {
151  alarm->setTime(alarm->time().addSecs(diffsecs));
152  }
153  }*/
154 
155  if (recurs() && !first) {
156  d->mDtRecurrence = dtDue;
157  } else {
158  d->mDtDue = dtDue;
159  }
160 
161  if (recurs() && dtDue.isValid() && (!dtStart().isValid() || dtDue < recurrence()->startDateTime())) {
162  kDebug() << "To-do recurrences are now calculated against DTSTART. Fixing legacy to-do.";
163  setDtStart(dtDue);
164  }
165 
166  /*const Alarm::List& alarms = alarms();
167  for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next())
168  alarm->setAlarmStart(d->mDtDue);*/
169  setFieldDirty(FieldDtDue);
170  endUpdates();
171 }
172 
173 KDateTime Todo::dtDue(bool first) const
174 {
175  if (!hasDueDate()) {
176  return KDateTime();
177  }
178  if (recurs() && !first && d->mDtRecurrence.isValid()) {
179  return d->mDtRecurrence;
180  }
181 
182  return d->mDtDue;
183 }
184 
185 bool Todo::hasDueDate() const
186 {
187  return d->mDtDue.isValid();
188 }
189 
190 void Todo::setHasDueDate(bool f)
191 {
192  if (mReadOnly) {
193  return;
194  }
195  update();
196  if (!f) {
197  d->mDtDue = KDateTime();
198  d->mDtRecurrence = KDateTime();
199  }
200  setFieldDirty(FieldDtDue);
201  updated();
202 }
203 
204 bool Todo::hasStartDate() const
205 {
206  return IncidenceBase::dtStart().isValid() || d->mDtRecurrence.isValid();
207 }
208 
209 void Todo::setHasStartDate(bool f)
210 {
211  if (mReadOnly) {
212  return;
213  }
214 
215  update();
216  if (recurs() && !f) {
217  if (!comments().filter("NoStartDate").count()) {
218  addComment("NoStartDate"); //TODO: --> custom flag?
219  }
220  } else {
221  QString s("NoStartDate");
222  removeComment(s);
223  }
224  if (!f) {
225  setDtStart(KDateTime());
226  }
227  setFieldDirty(FieldDtStart);
228  updated();
229 }
230 
231 KDateTime Todo::dtStart() const
232 {
233  return dtStart(false);
234 }
235 
236 KDateTime Todo::dtStart(bool first) const
237 {
238  if (!hasStartDate()) {
239  return KDateTime();
240  }
241  if (recurs() && !first && d->mDtRecurrence.isValid()) {
242  KDateTime dt = d->mDtRecurrence.addDays(dtDue(true).daysTo(IncidenceBase::dtStart()));
243  dt.setTime(IncidenceBase::dtStart().time());
244  return dt;
245  } else {
246  return IncidenceBase::dtStart();
247  }
248 }
249 
250 void Todo::setDtStart(const KDateTime &dtStart)
251 {
252  Incidence::setDtStart(dtStart);
253 }
254 
255 bool Todo::isCompleted() const
256 {
257  return d->mPercentComplete == 100;
258 }
259 
260 void Todo::setCompleted(bool completed)
261 {
262  update();
263  if (completed) {
264  d->mPercentComplete = 100;
265  } else {
266  d->mPercentComplete = 0;
267  d->mCompleted = KDateTime();
268  }
269  setFieldDirty(FieldCompleted);
270  updated();
271 }
272 
273 KDateTime Todo::completed() const
274 {
275  if (hasCompletedDate()) {
276  return d->mCompleted;
277  } else {
278  return KDateTime();
279  }
280 }
281 
282 void Todo::setCompleted(const KDateTime &completed)
283 {
284  update();
285  if (!d->recurTodo(this)) {
286  d->mPercentComplete = 100;
287  d->mCompleted = completed.toUtc();
288  setFieldDirty(FieldCompleted);
289  }
290  updated();
291 }
292 
293 bool Todo::hasCompletedDate() const
294 {
295  return d->mCompleted.isValid();
296 }
297 
298 int Todo::percentComplete() const
299 {
300  return d->mPercentComplete;
301 }
302 
303 void Todo::setPercentComplete(int percent)
304 {
305  if (percent > 100) {
306  percent = 100;
307  } else if (percent < 0) {
308  percent = 0;
309  }
310 
311  update();
312  d->mPercentComplete = percent;
313  if (percent != 100) {
314  d->mCompleted = KDateTime();
315  }
316  setFieldDirty(FieldPercentComplete);
317  updated();
318 }
319 
320 bool Todo::isInProgress(bool first) const
321 {
322  if (isOverdue()) {
323  return false;
324  }
325 
326  if (d->mPercentComplete > 0) {
327  return true;
328  }
329 
330  if (hasStartDate() && hasDueDate()) {
331  if (allDay()) {
332  QDate currDate = QDate::currentDate();
333  if (dtStart(first).date() <= currDate && currDate < dtDue(first).date()) {
334  return true;
335  }
336  } else {
337  KDateTime currDate = KDateTime::currentUtcDateTime();
338  if (dtStart(first) <= currDate && currDate < dtDue(first)) {
339  return true;
340  }
341  }
342  }
343 
344  return false;
345 }
346 
347 bool Todo::isOpenEnded() const
348 {
349  if (!hasDueDate() && !isCompleted()) {
350  return true;
351  }
352  return false;
353 
354 }
355 
356 bool Todo::isNotStarted(bool first) const
357 {
358  if (d->mPercentComplete > 0) {
359  return false;
360  }
361 
362  if (!hasStartDate()) {
363  return false;
364  }
365 
366  if (allDay()) {
367  if (dtStart(first).date() >= QDate::currentDate()) {
368  return false;
369  }
370  } else {
371  if (dtStart(first) >= KDateTime::currentUtcDateTime()) {
372  return false;
373  }
374  }
375  return true;
376 }
377 
378 void Todo::shiftTimes(const KDateTime::Spec &oldSpec,
379  const KDateTime::Spec &newSpec)
380 {
381  Incidence::shiftTimes(oldSpec, newSpec);
382  d->mDtDue = d->mDtDue.toTimeSpec(oldSpec);
383  d->mDtDue.setTimeSpec(newSpec);
384  if (recurs()) {
385  d->mDtRecurrence = d->mDtRecurrence.toTimeSpec(oldSpec);
386  d->mDtRecurrence.setTimeSpec(newSpec);
387  }
388  if (hasCompletedDate()) {
389  d->mCompleted = d->mCompleted.toTimeSpec(oldSpec);
390  d->mCompleted.setTimeSpec(newSpec);
391  }
392 }
393 
394 void Todo::setDtRecurrence(const KDateTime &dt)
395 {
396  d->mDtRecurrence = dt;
397  setFieldDirty(FieldRecurrence);
398 }
399 
400 KDateTime Todo::dtRecurrence() const
401 {
402  return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue;
403 }
404 
405 bool Todo::recursOn(const QDate &date, const KDateTime::Spec &timeSpec) const
406 {
407  QDate today = QDate::currentDate();
408  return
409  Incidence::recursOn(date, timeSpec) &&
410  !(date < today && d->mDtRecurrence.date() < today &&
411  d->mDtRecurrence > recurrence()->startDateTime());
412 }
413 
414 bool Todo::isOverdue() const
415 {
416  if (!dtDue().isValid()) {
417  return false; // if it's never due, it can't be overdue
418  }
419 
420  const bool inPast = allDay() ?
421  dtDue().date() < QDate::currentDate() :
422  dtDue() < KDateTime::currentUtcDateTime();
423  return inPast && !isCompleted();
424 }
425 
426 void Todo::setAllDay(bool allday)
427 {
428  if (allday != allDay() && !mReadOnly) {
429  if (hasDueDate()) {
430  setFieldDirty(FieldDtDue);
431  }
432  Incidence::setAllDay(allday);
433  }
434 }
435 
436 //@cond PRIVATE
437 bool Todo::Private::recurTodo(Todo *todo)
438 {
439  if (todo && todo->recurs()) {
440  Recurrence *r = todo->recurrence();
441  const KDateTime recurrenceEndDateTime = r->endDateTime();
442  KDateTime nextOccurrenceDateTime = r->getNextDateTime(todo->dtDue());
443 
444  if ((r->duration() == -1 ||
445  (nextOccurrenceDateTime.isValid() && recurrenceEndDateTime.isValid() &&
446  nextOccurrenceDateTime <= recurrenceEndDateTime))) {
447  // We convert to the same timeSpec so we get the correct .date()
448  const KDateTime rightNow =
449  KDateTime::currentUtcDateTime().toTimeSpec(nextOccurrenceDateTime.timeSpec());
450  const bool isDateOnly = todo->allDay();
451 
452  /* Now we search for the occurrence that's _after_ the currentUtcDateTime, or
453  * if it's dateOnly, the occurrrence that's _during or after today_.
454  * The reason we use "<" for date only, but "<=" for ocurrences with time is that
455  * if it's date only, the user can still complete that ocurrence today, so that's
456  * the current ocurrence that needs completing.
457  */
458  while (!todo->recursAt(nextOccurrenceDateTime) ||
459  (!isDateOnly && nextOccurrenceDateTime <= rightNow) ||
460  (isDateOnly && nextOccurrenceDateTime.date() < rightNow.date())) {
461 
462  if (!nextOccurrenceDateTime.isValid() ||
463  (nextOccurrenceDateTime > recurrenceEndDateTime && r->duration() != -1)) {
464  return false;
465  }
466  nextOccurrenceDateTime = r->getNextDateTime(nextOccurrenceDateTime);
467  }
468 
469  todo->setDtRecurrence(nextOccurrenceDateTime);
470  todo->setCompleted(false);
471  todo->setRevision(todo->revision() + 1);
472 
473  return true;
474  }
475  }
476 
477  return false;
478 }
479 //@endcond
480 
481 bool Todo::accept(Visitor &v, IncidenceBase::Ptr incidence)
482 {
483  return v.visit(incidence.staticCast<Todo>());
484 }
485 
486 KDateTime Todo::dateTime(DateTimeRole role) const
487 {
488  switch (role) {
489  case RoleAlarmStartOffset:
490  return dtStart();
491  case RoleAlarmEndOffset:
492  return dtDue();
493  case RoleSort:
494  // Sorting to-dos first compares dtDue, then dtStart if
495  // dtDue doesn't exist
496  return hasDueDate() ? dtDue() : dtStart();
497  case RoleCalendarHashing:
498  return dtDue();
499  case RoleStartTimeZone:
500  return dtStart();
501  case RoleEndTimeZone:
502  return dtDue();
503  case RoleEndRecurrenceBase:
504  return dtDue();
505  case RoleDisplayStart:
506  case RoleDisplayEnd:
507  return dtDue();
508  case RoleAlarm:
509  if (alarms().isEmpty()) {
510  return KDateTime();
511  } else {
512  Alarm::Ptr alarm = alarms().first();
513  if (alarm->hasStartOffset() && hasStartDate()) {
514  return dtStart();
515  } else if (alarm->hasEndOffset() && hasDueDate()) {
516  return dtDue();
517  } else {
518  // The application shouldn't add alarms on to-dos without dates.
519  return KDateTime();
520  }
521  }
522  case RoleRecurrenceStart:
523  if (dtStart().isValid()) {
524  return dtStart();
525  }
526  return dtDue(); //For the sake of backwards compatibility
527  //where we calculated recurrences based on dtDue
528  case RoleEnd:
529  return dtDue();
530  default:
531  return KDateTime();
532  }
533 }
534 
535 void Todo::setDateTime(const KDateTime &dateTime, DateTimeRole role)
536 {
537  switch (role) {
538  case RoleDnD:
539  setDtDue(dateTime);
540  break;
541  case RoleEnd:
542  setDtDue(dateTime, true);
543  break;
544  default:
545  kDebug() << "Unhandled role" << role;
546  }
547 }
548 
549 void Todo::virtual_hook(int id, void *data)
550 {
551  Q_UNUSED(id);
552  Q_UNUSED(data);
553  Q_ASSERT(false);
554 }
555 
556 QLatin1String Todo::mimeType() const
557 {
558  return Todo::todoMimeType();
559 }
560 
561 QLatin1String Todo::todoMimeType()
562 {
563  return QLatin1String("application/x-vnd.akonadi.calendar.todo");
564 }
565 
566 QLatin1String Todo::iconName(const KDateTime &recurrenceId) const
567 {
568  KDateTime occurrenceDT = recurrenceId;
569 
570  if (recurs() && occurrenceDT.isDateOnly()) {
571  occurrenceDT.setTime(QTime(0, 0));
572  }
573 
574  const bool usesCompletedTaskPixmap = isCompleted() ||
575  (recurs() && occurrenceDT.isValid() &&
576  occurrenceDT < dtDue(false));
577 
578  if (usesCompletedTaskPixmap) {
579  return QLatin1String("task-complete");
580  } else {
581  return QLatin1String("view-calendar-tasks");
582  }
583 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Fri Jan 17 2014 22:11:59 by doxygen 1.8.3.1 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.11.5 API Reference

Skip menu "kdepimlibs-4.11.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