KCalCore Library
incidencebase.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the kcalcore library. 00003 00004 Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org> 00005 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 00006 Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 00007 Contact: Alvaro Manera <alvaro.manera@nokia.com> 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00037 #include "incidencebase.h" 00038 #include "calformat.h" 00039 #include "visitor.h" 00040 00041 #include <QDebug> 00042 00043 #include <KUrl> 00044 00045 #include <QtCore/QStringList> 00046 00047 using namespace KCalCore; 00048 00053 //@cond PRIVATE 00054 class KCalCore::IncidenceBase::Private 00055 { 00056 public: 00057 Private() 00058 : mOrganizer( new Person() ), 00059 mUpdateGroupLevel( 0 ), 00060 mUpdatedPending( false ), 00061 mAllDay( true ), 00062 mHasDuration( false ) 00063 {} 00064 00065 Private( const Private &other ) 00066 : mUpdateGroupLevel( 0 ), 00067 mUpdatedPending( false ), 00068 mAllDay( true ), 00069 mHasDuration( false ) 00070 { 00071 init( other ); 00072 } 00073 00074 ~Private() 00075 { 00076 } 00077 00078 void init( const Private &other ); 00079 00080 KDateTime mLastModified; // incidence last modified date 00081 KDateTime mDtStart; // incidence start time 00082 Person::Ptr mOrganizer; // incidence person (owner) 00083 QString mUid; // incidence unique id 00084 Duration mDuration; // incidence duration 00085 int mUpdateGroupLevel; // if non-zero, suppresses update() calls 00086 bool mUpdatedPending; // true if an update has occurred since startUpdates() 00087 bool mAllDay; // true if the incidence is all-day 00088 bool mHasDuration; // true if the incidence has a duration 00089 Attendee::List mAttendees; // list of incidence attendees 00090 QStringList mComments; // list of incidence comments 00091 QStringList mContacts; // list of incidence contacts 00092 QList<IncidenceObserver*> mObservers; // list of incidence observers 00093 QSet<Field> mDirtyFields; // Fields that changed since last time the incidence was created 00094 // or since resetDirtyFlags() was called 00095 }; 00096 00097 void IncidenceBase::Private::init( const Private &other ) 00098 { 00099 mLastModified = other.mLastModified; 00100 mDtStart = other.mDtStart; 00101 mOrganizer = other.mOrganizer; 00102 mUid = other.mUid; 00103 mDuration = other.mDuration; 00104 mAllDay = other.mAllDay; 00105 mHasDuration = other.mHasDuration; 00106 00107 mComments = other.mComments; 00108 mContacts = other.mContacts; 00109 00110 mAttendees.clear(); 00111 Attendee::List::ConstIterator it; 00112 for ( it = other.mAttendees.constBegin(); it != other.mAttendees.constEnd(); ++it ) { 00113 mAttendees.append( Attendee::Ptr( new Attendee( *(*it) ) ) ); 00114 } 00115 } 00116 //@endcond 00117 00118 IncidenceBase::IncidenceBase() 00119 : d( new KCalCore::IncidenceBase::Private ) 00120 { 00121 mReadOnly = false; 00122 setUid( CalFormat::createUniqueId() ); 00123 } 00124 00125 IncidenceBase::IncidenceBase( const IncidenceBase &i ) 00126 : CustomProperties( i ), 00127 d( new KCalCore::IncidenceBase::Private( *i.d ) ) 00128 { 00129 mReadOnly = i.mReadOnly; 00130 } 00131 00132 IncidenceBase::~IncidenceBase() 00133 { 00134 delete d; 00135 } 00136 00137 IncidenceBase &IncidenceBase::operator=( const IncidenceBase &other ) 00138 { 00139 Q_ASSERT( type() == other.type() ); 00140 00141 startUpdates(); 00142 00143 // assign is virtual, will call the derived class's 00144 IncidenceBase &ret = assign( other ); 00145 endUpdates(); 00146 return ret; 00147 } 00148 00149 IncidenceBase &IncidenceBase::assign( const IncidenceBase &other ) 00150 { 00151 CustomProperties::operator=( other ); 00152 d->init( *other.d ); 00153 mReadOnly = other.mReadOnly; 00154 d->mDirtyFields.clear(); 00155 d->mDirtyFields.insert( FieldUnknown ); 00156 return *this; 00157 } 00158 00159 bool IncidenceBase::operator==( const IncidenceBase &i2 ) const 00160 { 00161 if ( i2.type() != type() ) { 00162 return false; 00163 } else { 00164 // equals is virtual, so here we're calling the derived class method 00165 return equals( i2 ); 00166 } 00167 } 00168 00169 bool IncidenceBase::operator!=( const IncidenceBase &i2 ) const 00170 { 00171 return !operator==( i2 ); 00172 } 00173 00174 bool IncidenceBase::equals( const IncidenceBase &i2 ) const 00175 { 00176 if ( attendees().count() != i2.attendees().count() ) { 00177 return false; 00178 } 00179 00180 Attendee::List al1 = attendees(); 00181 Attendee::List al2 = i2.attendees(); 00182 Attendee::List::ConstIterator a1 = al1.constBegin(); 00183 Attendee::List::ConstIterator a2 = al2.constBegin(); 00184 //TODO Does the order of attendees in the list really matter? 00185 //Please delete this comment if you know it's ok, kthx 00186 for ( ; a1 != al1.constEnd() && a2 != al2.constEnd(); ++a1, ++a2 ) { 00187 if ( !( **a1 == **a2 ) ) { 00188 return false; 00189 } 00190 } 00191 00192 if ( !CustomProperties::operator==( i2 ) ) { 00193 return false; 00194 } 00195 00196 return 00197 ( ( dtStart() == i2.dtStart() ) || 00198 ( !dtStart().isValid() && !i2.dtStart().isValid() ) ) && 00199 *( organizer().data() ) == *( i2.organizer().data() ) && 00200 uid() == i2.uid() && 00201 // Don't compare lastModified, otherwise the operator is not 00202 // of much use. We are not comparing for identity, after all. 00203 allDay() == i2.allDay() && 00204 duration() == i2.duration() && 00205 hasDuration() == i2.hasDuration(); 00206 // no need to compare mObserver 00207 } 00208 00209 bool IncidenceBase::accept( Visitor &v, IncidenceBase::Ptr incidence ) 00210 { 00211 Q_UNUSED( v ); 00212 Q_UNUSED( incidence ); 00213 return false; 00214 } 00215 00216 void IncidenceBase::setUid( const QString &uid ) 00217 { 00218 update(); 00219 d->mUid = uid; 00220 d->mDirtyFields.insert( FieldUid ); 00221 updated(); 00222 } 00223 00224 QString IncidenceBase::uid() const 00225 { 00226 return d->mUid; 00227 } 00228 00229 void IncidenceBase::setLastModified( const KDateTime &lm ) 00230 { 00231 // DON'T! updated() because we call this from 00232 // Calendar::updateEvent(). 00233 00234 d->mDirtyFields.insert( FieldLastModified ); 00235 00236 // Convert to UTC and remove milliseconds part. 00237 KDateTime current = lm.toUtc(); 00238 QTime t = current.time(); 00239 t.setHMS( t.hour(), t.minute(), t.second(), 0 ); 00240 current.setTime( t ); 00241 00242 d->mLastModified = current; 00243 } 00244 00245 KDateTime IncidenceBase::lastModified() const 00246 { 00247 return d->mLastModified; 00248 } 00249 00250 void IncidenceBase::setOrganizer( const Person::Ptr &o ) 00251 { 00252 update(); 00253 // we don't check for readonly here, because it is 00254 // possible that by setting the organizer we are changing 00255 // the event's readonly status... 00256 d->mOrganizer = o; 00257 00258 d->mDirtyFields.insert( FieldOrganizer ); 00259 00260 updated(); 00261 } 00262 00263 void IncidenceBase::setOrganizer( const QString &o ) 00264 { 00265 QString mail( o ); 00266 if ( mail.startsWith( QLatin1String( "MAILTO:" ), Qt::CaseInsensitive ) ) { 00267 mail = mail.remove( 0, 7 ); 00268 } 00269 00270 // split the string into full name plus email. 00271 const Person::Ptr organizer = Person::fromFullName( mail ); 00272 setOrganizer( organizer ); 00273 } 00274 00275 Person::Ptr IncidenceBase::organizer() const 00276 { 00277 return d->mOrganizer; 00278 } 00279 00280 void IncidenceBase::setReadOnly( bool readOnly ) 00281 { 00282 mReadOnly = readOnly; 00283 } 00284 00285 bool IncidenceBase::isReadOnly() const 00286 { 00287 return mReadOnly; 00288 } 00289 00290 void IncidenceBase::setDtStart( const KDateTime &dtStart ) 00291 { 00292 // if ( mReadOnly ) return; 00293 update(); 00294 d->mDtStart = dtStart; 00295 d->mAllDay = dtStart.isDateOnly(); 00296 d->mDirtyFields.insert( FieldDtStart ); 00297 updated(); 00298 } 00299 00300 KDateTime IncidenceBase::dtStart() const 00301 { 00302 return d->mDtStart; 00303 } 00304 00305 bool IncidenceBase::allDay() const 00306 { 00307 return d->mAllDay; 00308 } 00309 00310 void IncidenceBase::setAllDay( bool f ) 00311 { 00312 if ( mReadOnly || f == d->mAllDay ) { 00313 return; 00314 } 00315 update(); 00316 d->mAllDay = f; 00317 if ( d->mDtStart.isValid() ) { 00318 d->mDirtyFields.insert( FieldDtStart ); 00319 } 00320 updated(); 00321 } 00322 00323 void IncidenceBase::shiftTimes( const KDateTime::Spec &oldSpec, 00324 const KDateTime::Spec &newSpec ) 00325 { 00326 update(); 00327 d->mDtStart = d->mDtStart.toTimeSpec( oldSpec ); 00328 d->mDtStart.setTimeSpec( newSpec ); 00329 d->mDirtyFields.insert( FieldDtStart ); 00330 d->mDirtyFields.insert( FieldDtEnd ); 00331 updated(); 00332 } 00333 00334 void IncidenceBase::addComment( const QString &comment ) 00335 { 00336 d->mComments += comment; 00337 } 00338 00339 bool IncidenceBase::removeComment( const QString &comment ) 00340 { 00341 bool found = false; 00342 QStringList::Iterator i; 00343 00344 for ( i = d->mComments.begin(); !found && i != d->mComments.end(); ++i ) { 00345 if ( (*i) == comment ) { 00346 found = true; 00347 d->mComments.erase( i ); 00348 } 00349 } 00350 00351 if ( found ) { 00352 d->mDirtyFields.insert( FieldComment ); 00353 } 00354 00355 return found; 00356 } 00357 00358 void IncidenceBase::clearComments() 00359 { 00360 d->mDirtyFields.insert( FieldComment ); 00361 d->mComments.clear(); 00362 } 00363 00364 QStringList IncidenceBase::comments() const 00365 { 00366 return d->mComments; 00367 } 00368 00369 void IncidenceBase::addContact( const QString &contact ) 00370 { 00371 if ( !contact.isEmpty() ) { 00372 d->mContacts += contact; 00373 d->mDirtyFields.insert( FieldContact ); 00374 } 00375 } 00376 00377 bool IncidenceBase::removeContact( const QString &contact ) 00378 { 00379 bool found = false; 00380 QStringList::Iterator i; 00381 00382 for ( i = d->mContacts.begin(); !found && i != d->mContacts.end(); ++i ) { 00383 if ( (*i) == contact ) { 00384 found = true; 00385 d->mContacts.erase( i ); 00386 } 00387 } 00388 00389 if ( found ) { 00390 d->mDirtyFields.insert( FieldContact ); 00391 } 00392 00393 return found; 00394 } 00395 00396 void IncidenceBase::clearContacts() 00397 { 00398 d->mDirtyFields.insert( FieldContact ); 00399 d->mContacts.clear(); 00400 } 00401 00402 QStringList IncidenceBase::contacts() const 00403 { 00404 return d->mContacts; 00405 } 00406 00407 void IncidenceBase::addAttendee( const Attendee::Ptr &a, bool doupdate ) 00408 { 00409 if ( !a || mReadOnly ) { 00410 return; 00411 } 00412 00413 Q_ASSERT( !d->mAttendees.contains( a ) ); 00414 00415 if ( doupdate ) { 00416 update(); 00417 } 00418 if ( a->name().left(7).toUpper() == "MAILTO:" ) { 00419 a->setName( a->name().remove( 0, 7 ) ); 00420 } 00421 00422 /* If Uid is empty, just use the pointer to Attendee (encoded to 00423 * string) as Uid. Only thing that matters is that the Uid is unique 00424 * insofar IncidenceBase is concerned, and this does that (albeit 00425 * not very nicely). If these are ever saved to disk, should use 00426 * (considerably more expensive) CalFormat::createUniqueId(). As Uid 00427 * is not part of Attendee in iCal std, it's fairly safe bet that 00428 * these will never hit disc though so faster generation speed is 00429 * more important than actually being forever unique.*/ 00430 if ( a->uid().isEmpty() ) { 00431 a->setUid( QString::number( (qlonglong)a.data() ) ); 00432 } 00433 00434 d->mAttendees.append( a ); 00435 if ( doupdate ) { 00436 d->mDirtyFields.insert( FieldAttendees ); 00437 updated(); 00438 } 00439 } 00440 00441 void IncidenceBase::deleteAttendee( const Attendee::Ptr &a, bool doupdate ) 00442 { 00443 if ( !a || mReadOnly ) { 00444 return; 00445 } 00446 00447 int index = d->mAttendees.indexOf( a ); 00448 if ( index >= 0 ) { 00449 if ( doupdate ) { 00450 update(); 00451 } 00452 00453 d->mAttendees.remove( index ); 00454 00455 if ( doupdate ) { 00456 d->mDirtyFields.insert( FieldAttendees ); 00457 updated(); 00458 } 00459 } 00460 } 00461 00462 Attendee::List IncidenceBase::attendees() const 00463 { 00464 return d->mAttendees; 00465 } 00466 00467 int IncidenceBase::attendeeCount() const 00468 { 00469 return d->mAttendees.count(); 00470 } 00471 00472 void IncidenceBase::clearAttendees() 00473 { 00474 if ( mReadOnly ) { 00475 return; 00476 } 00477 d->mDirtyFields.insert( FieldAttendees ); 00478 d->mAttendees.clear(); 00479 } 00480 00481 Attendee::Ptr IncidenceBase::attendeeByMail( const QString &email ) const 00482 { 00483 Attendee::List::ConstIterator it; 00484 for ( it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it ) { 00485 if ( (*it)->email() == email ) { 00486 return *it; 00487 } 00488 } 00489 00490 return Attendee::Ptr(); 00491 } 00492 00493 Attendee::Ptr IncidenceBase::attendeeByMails( const QStringList &emails, 00494 const QString &email ) const 00495 { 00496 QStringList mails = emails; 00497 if ( !email.isEmpty() ) { 00498 mails.append( email ); 00499 } 00500 00501 Attendee::List::ConstIterator itA; 00502 for ( itA = d->mAttendees.constBegin(); itA != d->mAttendees.constEnd(); ++itA ) { 00503 for ( QStringList::const_iterator it = mails.constBegin(); it != mails.constEnd(); ++it ) { 00504 if ( (*itA)->email() == (*it) ) { 00505 return *itA; 00506 } 00507 } 00508 } 00509 00510 return Attendee::Ptr(); 00511 } 00512 00513 Attendee::Ptr IncidenceBase::attendeeByUid( const QString &uid ) const 00514 { 00515 Attendee::List::ConstIterator it; 00516 for ( it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it ) { 00517 if ( (*it)->uid() == uid ) { 00518 return *it; 00519 } 00520 } 00521 00522 return Attendee::Ptr(); 00523 } 00524 00525 void IncidenceBase::setDuration( const Duration &duration ) 00526 { 00527 update(); 00528 d->mDuration = duration; 00529 setHasDuration( true ); 00530 d->mDirtyFields.insert( FieldDuration ); 00531 updated(); 00532 } 00533 00534 Duration IncidenceBase::duration() const 00535 { 00536 return d->mDuration; 00537 } 00538 00539 void IncidenceBase::setHasDuration( bool hasDuration ) 00540 { 00541 d->mHasDuration = hasDuration; 00542 } 00543 00544 bool IncidenceBase::hasDuration() const 00545 { 00546 return d->mHasDuration; 00547 } 00548 00549 void IncidenceBase::registerObserver( IncidenceBase::IncidenceObserver *observer ) 00550 { 00551 if ( observer && !d->mObservers.contains( observer ) ) { 00552 d->mObservers.append( observer ); 00553 } 00554 } 00555 00556 void IncidenceBase::unRegisterObserver( IncidenceBase::IncidenceObserver *observer ) 00557 { 00558 d->mObservers.removeAll( observer ); 00559 } 00560 00561 void IncidenceBase::update() 00562 { 00563 if ( !d->mUpdateGroupLevel ) { 00564 d->mUpdatedPending = true; 00565 KDateTime rid = recurrenceId(); 00566 foreach ( IncidenceObserver *o, d->mObservers ) { 00567 o->incidenceUpdate( uid(), rid ); 00568 } 00569 } 00570 } 00571 00572 void IncidenceBase::updated() 00573 { 00574 if ( d->mUpdateGroupLevel ) { 00575 d->mUpdatedPending = true; 00576 } else { 00577 KDateTime rid = recurrenceId(); 00578 foreach ( IncidenceObserver *o, d->mObservers ) { 00579 o->incidenceUpdated( uid(), rid ); 00580 } 00581 } 00582 } 00583 00584 void IncidenceBase::startUpdates() 00585 { 00586 update(); 00587 ++d->mUpdateGroupLevel; 00588 } 00589 00590 void IncidenceBase::endUpdates() 00591 { 00592 if ( d->mUpdateGroupLevel > 0 ) { 00593 if ( --d->mUpdateGroupLevel == 0 && d->mUpdatedPending ) { 00594 d->mUpdatedPending = false; 00595 updated(); 00596 } 00597 } 00598 } 00599 00600 void IncidenceBase::customPropertyUpdate() 00601 { 00602 update(); 00603 } 00604 00605 void IncidenceBase::customPropertyUpdated() 00606 { 00607 updated(); 00608 } 00609 00610 KDateTime IncidenceBase::recurrenceId() const 00611 { 00612 return KDateTime(); 00613 } 00614 00615 void IncidenceBase::resetDirtyFields() 00616 { 00617 d->mDirtyFields.clear(); 00618 } 00619 00620 QSet<IncidenceBase::Field> IncidenceBase::dirtyFields() const 00621 { 00622 return d->mDirtyFields; 00623 } 00624 00625 void IncidenceBase::setFieldDirty( IncidenceBase::Field field ) 00626 { 00627 d->mDirtyFields.insert( field ); 00628 } 00629 00630 KUrl IncidenceBase::uri() const 00631 { 00632 return KUrl( QString( "urn:x-ical:" ) + uid() ); 00633 } 00634 00635 void IncidenceBase::setDirtyFields( const QSet<IncidenceBase::Field> &dirtyFields ) 00636 { 00637 d->mDirtyFields = dirtyFields; 00638 } 00639 00640 IncidenceBase::IncidenceObserver::~IncidenceObserver() 00641 { 00642 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:35:41 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:35:41 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.