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

KCalCore Library

  • kcalcore
incidencebase.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalcore library.
3 
4  Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>
5  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6  Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
7  Contact: Alvaro Manera <alvaro.manera@nokia.com>
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Library General Public
11  License as published by the Free Software Foundation; either
12  version 2 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Library General Public License for more details.
18 
19  You should have received a copy of the GNU Library General Public License
20  along with this library; see the file COPYING.LIB. If not, write to
21  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  Boston, MA 02110-1301, USA.
23 */
37 #include "incidencebase.h"
38 #include "calformat.h"
39 #include "visitor.h"
40 
41 #include <QTime>
42 #include <KDebug>
43 #include <KUrl>
44 
45 #include <QtCore/QStringList>
46 
47 using namespace KCalCore;
48 
53 //@cond PRIVATE
54 class KCalCore::IncidenceBase::Private
55 {
56 public:
57  Private()
58  : mOrganizer(0),
59  mUpdateGroupLevel(0),
60  mUpdatedPending(false),
61  mAllDay(true),
62  mHasDuration(false)
63  {}
64 
65  Private(const Private &other)
66  : mUpdateGroupLevel(0),
67  mUpdatedPending(false),
68  mAllDay(true),
69  mHasDuration(false)
70  {
71  init(other);
72  }
73 
74  ~Private()
75  {
76  }
77 
78  void init(const Private &other);
79 
80  KDateTime mLastModified; // incidence last modified date
81  KDateTime mDtStart; // incidence start time
82  Person::Ptr mOrganizer; // incidence person (owner)
83  QString mUid; // incidence unique id
84  Duration mDuration; // incidence duration
85  int mUpdateGroupLevel; // if non-zero, suppresses update() calls
86  bool mUpdatedPending; // true if an update has occurred since startUpdates()
87  bool mAllDay; // true if the incidence is all-day
88  bool mHasDuration; // true if the incidence has a duration
89  Attendee::List mAttendees; // list of incidence attendees
90  QStringList mComments; // list of incidence comments
91  QStringList mContacts; // list of incidence contacts
92  QList<IncidenceObserver*> mObservers; // list of incidence observers
93  QSet<Field> mDirtyFields; // Fields that changed since last time the incidence was created
94  // or since resetDirtyFlags() was called
95 };
96 
97 void IncidenceBase::Private::init(const Private &other)
98 {
99  mLastModified = other.mLastModified;
100  mDtStart = other.mDtStart;
101  mOrganizer = other.mOrganizer;
102  mUid = other.mUid;
103  mDuration = other.mDuration;
104  mAllDay = other.mAllDay;
105  mHasDuration = other.mHasDuration;
106 
107  mComments = other.mComments;
108  mContacts = other.mContacts;
109 
110  mAttendees.clear();
111  Attendee::List::ConstIterator it;
112  for (it = other.mAttendees.constBegin(); it != other.mAttendees.constEnd(); ++it) {
113  mAttendees.append(Attendee::Ptr(new Attendee(*(*it))));
114  }
115 }
116 //@endcond
117 
118 IncidenceBase::IncidenceBase()
119  : d(new KCalCore::IncidenceBase::Private)
120 {
121  mReadOnly = false;
122  setUid(CalFormat::createUniqueId());
123 }
124 
125 IncidenceBase::IncidenceBase(const IncidenceBase &i)
126  : CustomProperties(i),
127  d(new KCalCore::IncidenceBase::Private(*i.d))
128 {
129  mReadOnly = i.mReadOnly;
130 }
131 
132 IncidenceBase::~IncidenceBase()
133 {
134  delete d;
135 }
136 
137 IncidenceBase &IncidenceBase::operator=(const IncidenceBase &other)
138 {
139  Q_ASSERT(type() == other.type());
140 
141  startUpdates();
142 
143  // assign is virtual, will call the derived class's
144  IncidenceBase &ret = assign(other);
145  endUpdates();
146  return ret;
147 }
148 
149 IncidenceBase &IncidenceBase::assign(const IncidenceBase &other)
150 {
151  CustomProperties::operator=(other);
152 
153  const bool uidChanged = other.uid() != uid();
154 
155  d->init(*other.d);
156  mReadOnly = other.mReadOnly;
157  d->mDirtyFields.clear();
158  d->mDirtyFields.insert(FieldUnknown); // Means stuff might have changed.
159 
160  // Observers using the observer interface have no way of finding out if there
161  // was a uid change so, exceptionally, lets set this field dirty.
162  if (uidChanged)
163  d->mDirtyFields.insert(FieldUid);
164 
165  return *this;
166 }
167 
168 bool IncidenceBase::operator==(const IncidenceBase &i2) const
169 {
170  if (i2.type() != type()) {
171  return false;
172  } else {
173  // equals is virtual, so here we're calling the derived class method
174  return equals(i2);
175  }
176 }
177 
178 bool IncidenceBase::operator!=(const IncidenceBase &i2) const
179 {
180  return !operator==(i2);
181 }
182 
183 bool IncidenceBase::equals(const IncidenceBase &i2) const
184 {
185  if (attendees().count() != i2.attendees().count()) {
186  return false;
187  }
188 
189  Attendee::List al1 = attendees();
190  Attendee::List al2 = i2.attendees();
191  Attendee::List::ConstIterator a1 = al1.constBegin();
192  Attendee::List::ConstIterator a2 = al2.constBegin();
193  //TODO Does the order of attendees in the list really matter?
194  //Please delete this comment if you know it's ok, kthx
195  for (; a1 != al1.constEnd() && a2 != al2.constEnd(); ++a1, ++a2) {
196  if (!(**a1 == **a2)) {
197  return false;
198  }
199  }
200 
201  if (!CustomProperties::operator==(i2)) {
202  return false;
203  }
204 
205  return
206  ((dtStart() == i2.dtStart()) ||
207  (!dtStart().isValid() && !i2.dtStart().isValid())) &&
208  *(organizer().data()) == *(i2.organizer().data()) &&
209  uid() == i2.uid() &&
210  // Don't compare lastModified, otherwise the operator is not
211  // of much use. We are not comparing for identity, after all.
212  allDay() == i2.allDay() &&
213  duration() == i2.duration() &&
214  hasDuration() == i2.hasDuration();
215  // no need to compare mObserver
216 }
217 
218 bool IncidenceBase::accept(Visitor &v, IncidenceBase::Ptr incidence)
219 {
220  Q_UNUSED(v);
221  Q_UNUSED(incidence);
222  return false;
223 }
224 
225 void IncidenceBase::setUid(const QString &uid)
226 {
227  update();
228  d->mUid = uid;
229  d->mDirtyFields.insert(FieldUid);
230  updated();
231 }
232 
233 QString IncidenceBase::uid() const
234 {
235  return d->mUid;
236 }
237 
238 void IncidenceBase::setLastModified(const KDateTime &lm)
239 {
240  // DON'T! updated() because we call this from
241  // Calendar::updateEvent().
242 
243  d->mDirtyFields.insert(FieldLastModified);
244 
245  // Convert to UTC and remove milliseconds part.
246  KDateTime current = lm.toUtc();
247  QTime t = current.time();
248  t.setHMS(t.hour(), t.minute(), t.second(), 0);
249  current.setTime(t);
250 
251  d->mLastModified = current;
252 }
253 
254 KDateTime IncidenceBase::lastModified() const
255 {
256  return d->mLastModified;
257 }
258 
259 void IncidenceBase::setOrganizer(const Person::Ptr &organizer)
260 {
261  if (organizer) {
262  update();
263  // we don't check for readonly here, because it is
264  // possible that by setting the organizer we are changing
265  // the event's readonly status...
266  d->mOrganizer = organizer;
267 
268  d->mDirtyFields.insert(FieldOrganizer);
269 
270  updated();
271  }
272 }
273 
274 void IncidenceBase::setOrganizer(const QString &o)
275 {
276  QString mail(o);
277  if (mail.startsWith(QLatin1String("MAILTO:"), Qt::CaseInsensitive)) {
278  mail = mail.remove(0, 7);
279  }
280 
281  // split the string into full name plus email.
282  const Person::Ptr organizer = Person::fromFullName(mail);
283  setOrganizer(organizer);
284 }
285 
286 Person::Ptr IncidenceBase::organizer() const
287 {
288  if (!d->mOrganizer)
289  d->mOrganizer = Person::Ptr(new Person()); // init at first use only to save memory
290 
291  return d->mOrganizer;
292 }
293 
294 void IncidenceBase::setReadOnly(bool readOnly)
295 {
296  mReadOnly = readOnly;
297 }
298 
299 bool IncidenceBase::isReadOnly() const
300 {
301  return mReadOnly;
302 }
303 
304 void IncidenceBase::setDtStart(const KDateTime &dtStart)
305 {
306 // if ( mReadOnly ) return;
307 
308  if (!dtStart.isValid() && type() != IncidenceBase::TypeTodo) {
309  kWarning() << "Invalid dtStart";
310  }
311 
312  update();
313  d->mDtStart = dtStart;
314  d->mAllDay = dtStart.isDateOnly();
315  d->mDirtyFields.insert(FieldDtStart);
316  updated();
317 }
318 
319 KDateTime IncidenceBase::dtStart() const
320 {
321  return d->mDtStart;
322 }
323 
324 bool IncidenceBase::allDay() const
325 {
326  return d->mAllDay;
327 }
328 
329 void IncidenceBase::setAllDay(bool f)
330 {
331  if (mReadOnly || f == d->mAllDay) {
332  return;
333  }
334  update();
335  d->mAllDay = f;
336  if (d->mDtStart.isValid()) {
337  d->mDirtyFields.insert(FieldDtStart);
338  }
339  updated();
340 }
341 
342 void IncidenceBase::shiftTimes(const KDateTime::Spec &oldSpec,
343  const KDateTime::Spec &newSpec)
344 {
345  update();
346  d->mDtStart = d->mDtStart.toTimeSpec(oldSpec);
347  d->mDtStart.setTimeSpec(newSpec);
348  d->mDirtyFields.insert(FieldDtStart);
349  d->mDirtyFields.insert(FieldDtEnd);
350  updated();
351 }
352 
353 void IncidenceBase::addComment(const QString &comment)
354 {
355  d->mComments += comment;
356 }
357 
358 bool IncidenceBase::removeComment(const QString &comment)
359 {
360  bool found = false;
361  QStringList::Iterator i;
362 
363  for (i = d->mComments.begin(); !found && i != d->mComments.end(); ++i) {
364  if ((*i) == comment) {
365  found = true;
366  d->mComments.erase(i);
367  }
368  }
369 
370  if (found) {
371  d->mDirtyFields.insert(FieldComment);
372  }
373 
374  return found;
375 }
376 
377 void IncidenceBase::clearComments()
378 {
379  d->mDirtyFields.insert(FieldComment);
380  d->mComments.clear();
381 }
382 
383 QStringList IncidenceBase::comments() const
384 {
385  return d->mComments;
386 }
387 
388 void IncidenceBase::addContact(const QString &contact)
389 {
390  if (!contact.isEmpty()) {
391  d->mContacts += contact;
392  d->mDirtyFields.insert(FieldContact);
393  }
394 }
395 
396 bool IncidenceBase::removeContact(const QString &contact)
397 {
398  bool found = false;
399  QStringList::Iterator i;
400 
401  for (i = d->mContacts.begin(); !found && i != d->mContacts.end(); ++i) {
402  if ((*i) == contact) {
403  found = true;
404  d->mContacts.erase(i);
405  }
406  }
407 
408  if (found) {
409  d->mDirtyFields.insert(FieldContact);
410  }
411 
412  return found;
413 }
414 
415 void IncidenceBase::clearContacts()
416 {
417  d->mDirtyFields.insert(FieldContact);
418  d->mContacts.clear();
419 }
420 
421 QStringList IncidenceBase::contacts() const
422 {
423  return d->mContacts;
424 }
425 
426 void IncidenceBase::addAttendee(const Attendee::Ptr &a, bool doupdate)
427 {
428  if (!a || mReadOnly) {
429  return;
430  }
431 
432  Q_ASSERT(!d->mAttendees.contains(a));
433 
434  if (doupdate) {
435  update();
436  }
437  if (a->name().left(7).toUpper() == "MAILTO:") {
438  a->setName(a->name().remove(0, 7));
439  }
440 
441  /* If Uid is empty, just use the pointer to Attendee (encoded to
442  * string) as Uid. Only thing that matters is that the Uid is unique
443  * insofar IncidenceBase is concerned, and this does that (albeit
444  * not very nicely). If these are ever saved to disk, should use
445  * (considerably more expensive) CalFormat::createUniqueId(). As Uid
446  * is not part of Attendee in iCal std, it's fairly safe bet that
447  * these will never hit disc though so faster generation speed is
448  * more important than actually being forever unique.*/
449  if (a->uid().isEmpty()) {
450  a->setUid(QString::number((qlonglong)a.data()));
451  }
452 
453  d->mAttendees.append(a);
454  if (doupdate) {
455  d->mDirtyFields.insert(FieldAttendees);
456  updated();
457  }
458 }
459 
460 void IncidenceBase::deleteAttendee(const Attendee::Ptr &a, bool doupdate)
461 {
462  if (!a || mReadOnly) {
463  return;
464  }
465 
466  int index = d->mAttendees.indexOf(a);
467  if (index >= 0) {
468  if (doupdate) {
469  update();
470  }
471 
472  d->mAttendees.remove(index);
473 
474  if (doupdate) {
475  d->mDirtyFields.insert(FieldAttendees);
476  updated();
477  }
478  }
479 }
480 
481 Attendee::List IncidenceBase::attendees() const
482 {
483  return d->mAttendees;
484 }
485 
486 int IncidenceBase::attendeeCount() const
487 {
488  return d->mAttendees.count();
489 }
490 
491 void IncidenceBase::clearAttendees()
492 {
493  if (mReadOnly) {
494  return;
495  }
496  d->mDirtyFields.insert(FieldAttendees);
497  d->mAttendees.clear();
498 }
499 
500 Attendee::Ptr IncidenceBase::attendeeByMail(const QString &email) const
501 {
502  Attendee::List::ConstIterator it;
503  for (it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it) {
504  if ((*it)->email() == email) {
505  return *it;
506  }
507  }
508 
509  return Attendee::Ptr();
510 }
511 
512 Attendee::Ptr IncidenceBase::attendeeByMails(const QStringList &emails,
513  const QString &email) const
514 {
515  QStringList mails = emails;
516  if (!email.isEmpty()) {
517  mails.append(email);
518  }
519 
520  Attendee::List::ConstIterator itA;
521  for (itA = d->mAttendees.constBegin(); itA != d->mAttendees.constEnd(); ++itA) {
522  for (QStringList::const_iterator it = mails.constBegin(); it != mails.constEnd(); ++it) {
523  if ((*itA)->email() == (*it)) {
524  return *itA;
525  }
526  }
527  }
528 
529  return Attendee::Ptr();
530 }
531 
532 Attendee::Ptr IncidenceBase::attendeeByUid(const QString &uid) const
533 {
534  Attendee::List::ConstIterator it;
535  for (it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it) {
536  if ((*it)->uid() == uid) {
537  return *it;
538  }
539  }
540 
541  return Attendee::Ptr();
542 }
543 
544 void IncidenceBase::setDuration(const Duration &duration)
545 {
546  update();
547  d->mDuration = duration;
548  setHasDuration(true);
549  d->mDirtyFields.insert(FieldDuration);
550  updated();
551 }
552 
553 Duration IncidenceBase::duration() const
554 {
555  return d->mDuration;
556 }
557 
558 void IncidenceBase::setHasDuration(bool hasDuration)
559 {
560  d->mHasDuration = hasDuration;
561 }
562 
563 bool IncidenceBase::hasDuration() const
564 {
565  return d->mHasDuration;
566 }
567 
568 void IncidenceBase::registerObserver(IncidenceBase::IncidenceObserver *observer)
569 {
570  if (observer && !d->mObservers.contains(observer)) {
571  d->mObservers.append(observer);
572  }
573 }
574 
575 void IncidenceBase::unRegisterObserver(IncidenceBase::IncidenceObserver *observer)
576 {
577  d->mObservers.removeAll(observer);
578 }
579 
580 void IncidenceBase::update()
581 {
582  if (!d->mUpdateGroupLevel) {
583  d->mUpdatedPending = true;
584  KDateTime rid = recurrenceId();
585  foreach(IncidenceObserver *o, d->mObservers) {
586  o->incidenceUpdate(uid(), rid);
587  }
588  }
589 }
590 
591 void IncidenceBase::updated()
592 {
593  if (d->mUpdateGroupLevel) {
594  d->mUpdatedPending = true;
595  } else {
596  const KDateTime rid = recurrenceId();
597  foreach(IncidenceObserver *o, d->mObservers) {
598  o->incidenceUpdated(uid(), rid);
599  }
600  }
601 }
602 
603 void IncidenceBase::startUpdates()
604 {
605  update();
606  ++d->mUpdateGroupLevel;
607 }
608 
609 void IncidenceBase::endUpdates()
610 {
611  if (d->mUpdateGroupLevel > 0) {
612  if (--d->mUpdateGroupLevel == 0 && d->mUpdatedPending) {
613  d->mUpdatedPending = false;
614  updated();
615  }
616  }
617 }
618 
619 void IncidenceBase::customPropertyUpdate()
620 {
621  update();
622 }
623 
624 void IncidenceBase::customPropertyUpdated()
625 {
626  updated();
627 }
628 
629 KDateTime IncidenceBase::recurrenceId() const
630 {
631  return KDateTime();
632 }
633 
634 void IncidenceBase::resetDirtyFields()
635 {
636  d->mDirtyFields.clear();
637 }
638 
639 QSet<IncidenceBase::Field> IncidenceBase::dirtyFields() const
640 {
641  return d->mDirtyFields;
642 }
643 
644 void IncidenceBase::setFieldDirty(IncidenceBase::Field field)
645 {
646  d->mDirtyFields.insert(field);
647 }
648 
649 KUrl IncidenceBase::uri() const
650 {
651  return KUrl(QString("urn:x-ical:") + uid());
652 }
653 
654 void IncidenceBase::setDirtyFields(const QSet<IncidenceBase::Field> &dirtyFields)
655 {
656  d->mDirtyFields = dirtyFields;
657 }
658 
659 IncidenceBase::IncidenceObserver::~IncidenceObserver()
660 {
661 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Thu Jan 9 2014 17:48:40 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