incidencebase.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the kcal library. 00003 00004 Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org> 00005 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00035 #include "incidencebase.h" 00036 #include "calformat.h" 00037 #include "incidenceformatter.h" 00038 00039 #include <kglobal.h> 00040 #include <klocale.h> 00041 #include <kdebug.h> 00042 #include <kurl.h> 00043 #include <ksystemtimezone.h> 00044 00045 #include <QtCore/QList> 00046 00047 using namespace KCal; 00048 00053 //@cond PRIVATE 00054 class KCal::IncidenceBase::Private 00055 { 00056 public: 00057 Private() 00058 : mUpdateGroupLevel( 0 ), 00059 mUpdatedPending( false ), 00060 mAllDay( true ), 00061 mHasDuration( false ) 00062 { mAttendees.setAutoDelete( true ); } 00063 00064 Private( const Private &other ) 00065 : mUpdateGroupLevel( 0 ), 00066 mUpdatedPending( false ), 00067 mAllDay( true ), 00068 mHasDuration( false ) 00069 { 00070 mAttendees.setAutoDelete( true ); 00071 init( other ); 00072 } 00073 00074 void init( const Private &other ); 00075 00076 KDateTime mLastModified; // incidence last modified date 00077 KDateTime mDtStart; // incidence start time 00078 Person mOrganizer; // incidence person (owner) 00079 QString mUid; // incidence unique id 00080 Duration mDuration; // incidence duration 00081 int mUpdateGroupLevel; // if non-zero, suppresses update() calls 00082 bool mUpdatedPending; // true if an update has occurred since startUpdates() 00083 bool mAllDay; // true if the incidence is all-day 00084 bool mHasDuration; // true if the incidence has a duration 00085 00086 Attendee::List mAttendees; // list of incidence attendees 00087 QStringList mComments; // list of incidence comments 00088 QList<IncidenceObserver*> mObservers; // list of incidence observers 00089 }; 00090 00091 void IncidenceBase::Private::init( const Private &other ) 00092 { 00093 mLastModified = other.mLastModified; 00094 mDtStart = other.mDtStart; 00095 mOrganizer = other.mOrganizer; 00096 mUid = other.mUid; 00097 mDuration = other.mDuration; 00098 mAllDay = other.mAllDay; 00099 mHasDuration = other.mHasDuration; 00100 mComments = other.mComments; 00101 00102 mAttendees.clearAll(); 00103 Attendee::List::ConstIterator it; 00104 for ( it = other.mAttendees.constBegin(); it != other.mAttendees.constEnd(); ++it ) { 00105 mAttendees.append( new Attendee( *(*it) ) ); 00106 } 00107 } 00108 //@endcond 00109 00110 IncidenceBase::IncidenceBase() 00111 : d( new KCal::IncidenceBase::Private ) 00112 { 00113 mReadOnly = false; 00114 00115 setUid( CalFormat::createUniqueId() ); 00116 } 00117 00118 IncidenceBase::IncidenceBase( const IncidenceBase &i ) 00119 : CustomProperties( i ), 00120 d( new KCal::IncidenceBase::Private( *i.d ) ) 00121 { 00122 mReadOnly = i.mReadOnly; 00123 } 00124 00125 IncidenceBase::~IncidenceBase() 00126 { 00127 delete d; 00128 } 00129 00130 IncidenceBase &IncidenceBase::operator=( const IncidenceBase &other ) 00131 { 00132 // check for self assignment 00133 if ( &other == this ) { 00134 return *this; 00135 } 00136 00137 CustomProperties::operator=( other ); 00138 d->init( *other.d ); 00139 mReadOnly = other.mReadOnly; 00140 return *this; 00141 } 00142 00143 bool IncidenceBase::operator==( const IncidenceBase &i2 ) const 00144 { 00145 if ( attendees().count() != i2.attendees().count() ) { 00146 return false; // no need to check further 00147 } 00148 00149 Attendee::List al1 = attendees(); 00150 Attendee::List al2 = i2.attendees(); 00151 Attendee::List::ConstIterator a1 = al1.constBegin(); 00152 Attendee::List::ConstIterator a2 = al2.constBegin(); 00153 //TODO Does the order of attendees in the list really matter? 00154 //Please delete this comment if you know it's ok, kthx 00155 for ( ; a1 != al1.constEnd() && a2 != al2.constEnd(); ++a1, ++a2 ) { 00156 if ( !( **a1 == **a2 ) ) { 00157 return false; 00158 } 00159 } 00160 00161 if ( !CustomProperties::operator == (i2) ) { 00162 return false; 00163 } 00164 00165 return 00166 dtStart() == i2.dtStart() && 00167 organizer() == i2.organizer() && 00168 uid() == i2.uid() && 00169 // Don't compare lastModified, otherwise the operator is not 00170 // of much use. We are not comparing for identity, after all. 00171 allDay() == i2.allDay() && 00172 duration() == i2.duration() && 00173 hasDuration() == i2.hasDuration(); 00174 // no need to compare mObserver 00175 } 00176 00177 void IncidenceBase::setUid( const QString &uid ) 00178 { 00179 d->mUid = uid; 00180 updated(); 00181 } 00182 00183 QString IncidenceBase::uid() const 00184 { 00185 return d->mUid; 00186 } 00187 00188 void IncidenceBase::setLastModified( const KDateTime &lm ) 00189 { 00190 // DON'T! updated() because we call this from 00191 // Calendar::updateEvent(). 00192 00193 // Convert to UTC and remove milliseconds part. 00194 KDateTime current = lm.toUtc(); 00195 QTime t = current.time(); 00196 t.setHMS( t.hour(), t.minute(), t.second(), 0 ); 00197 current.setTime( t ); 00198 00199 d->mLastModified = current; 00200 } 00201 00202 KDateTime IncidenceBase::lastModified() const 00203 { 00204 return d->mLastModified; 00205 } 00206 00207 void IncidenceBase::setOrganizer( const Person &o ) 00208 { 00209 // we don't check for readonly here, because it is 00210 // possible that by setting the organizer we are changing 00211 // the event's readonly status... 00212 d->mOrganizer = o; 00213 00214 updated(); 00215 } 00216 00217 void IncidenceBase::setOrganizer( const QString &o ) 00218 { 00219 QString mail( o ); 00220 if ( mail.startsWith( QLatin1String( "MAILTO:" ), Qt::CaseInsensitive ) ) { 00221 mail = mail.remove( 0, 7 ); 00222 } 00223 00224 // split the string into full name plus email. 00225 const Person organizer = Person::fromFullName( mail ); 00226 setOrganizer( organizer ); 00227 } 00228 00229 Person IncidenceBase::organizer() const 00230 { 00231 return d->mOrganizer; 00232 } 00233 00234 void IncidenceBase::setReadOnly( bool readOnly ) 00235 { 00236 mReadOnly = readOnly; 00237 } 00238 00239 void IncidenceBase::setDtStart( const KDateTime &dtStart ) 00240 { 00241 // if ( mReadOnly ) return; 00242 d->mDtStart = dtStart; 00243 d->mAllDay = dtStart.isDateOnly(); 00244 updated(); 00245 } 00246 00247 KDateTime IncidenceBase::dtStart() const 00248 { 00249 return d->mDtStart; 00250 } 00251 00252 QString IncidenceBase::dtStartTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const 00253 { 00254 if ( spec.isValid() ) { 00255 00256 QString timeZone; 00257 if ( spec.timeZone() != KSystemTimeZones::local() ) { 00258 timeZone = ' ' + spec.timeZone().name(); 00259 } 00260 00261 return KGlobal::locale()->formatTime( 00262 dtStart().toTimeSpec( spec ).time(), !shortfmt ) + timeZone; 00263 } else { 00264 return KGlobal::locale()->formatTime( dtStart().time(), !shortfmt ); 00265 } 00266 } 00267 00268 QString IncidenceBase::dtStartDateStr( bool shortfmt, const KDateTime::Spec &spec ) const 00269 { 00270 if ( spec.isValid() ) { 00271 00272 QString timeZone; 00273 if ( spec.timeZone() != KSystemTimeZones::local() ) { 00274 timeZone = ' ' + spec.timeZone().name(); 00275 } 00276 00277 return KGlobal::locale()->formatDate( 00278 dtStart().toTimeSpec( spec ).date(), 00279 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; 00280 } else { 00281 return KGlobal::locale()->formatDate( 00282 dtStart().date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); 00283 } 00284 } 00285 00286 QString IncidenceBase::dtStartStr( bool shortfmt, const KDateTime::Spec &spec ) const 00287 { 00288 if ( allDay() ) { 00289 return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec ); 00290 } 00291 00292 if ( spec.isValid() ) { 00293 00294 QString timeZone; 00295 if ( spec.timeZone() != KSystemTimeZones::local() ) { 00296 timeZone = ' ' + spec.timeZone().name(); 00297 } 00298 00299 return KGlobal::locale()->formatDateTime( 00300 dtStart().toTimeSpec( spec ).dateTime(), 00301 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; 00302 } else { 00303 return KGlobal::locale()->formatDateTime( 00304 dtStart().dateTime(), 00305 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); 00306 } 00307 } 00308 00309 bool IncidenceBase::allDay() const 00310 { 00311 return d->mAllDay; 00312 } 00313 00314 void IncidenceBase::setAllDay( bool f ) 00315 { 00316 if ( mReadOnly || f == d->mAllDay ) { 00317 return; 00318 } 00319 d->mAllDay = f; 00320 updated(); 00321 } 00322 00323 void IncidenceBase::shiftTimes( const KDateTime::Spec &oldSpec, 00324 const KDateTime::Spec &newSpec ) 00325 { 00326 d->mDtStart = d->mDtStart.toTimeSpec( oldSpec ); 00327 d->mDtStart.setTimeSpec( newSpec ); 00328 updated(); 00329 } 00330 00331 void IncidenceBase::addComment( const QString &comment ) 00332 { 00333 d->mComments += comment; 00334 } 00335 00336 bool IncidenceBase::removeComment( const QString &comment ) 00337 { 00338 bool found = false; 00339 QStringList::Iterator i; 00340 00341 for ( i = d->mComments.begin(); !found && i != d->mComments.end(); ++i ) { 00342 if ( (*i) == comment ) { 00343 found = true; 00344 d->mComments.erase( i ); 00345 } 00346 } 00347 00348 return found; 00349 } 00350 00351 void IncidenceBase::clearComments() 00352 { 00353 d->mComments.clear(); 00354 } 00355 00356 QStringList IncidenceBase::comments() const 00357 { 00358 return d->mComments; 00359 } 00360 00361 void IncidenceBase::addAttendee( Attendee *a, bool doupdate ) 00362 { 00363 if ( !a || mReadOnly ) { 00364 return; 00365 } 00366 00367 if ( a->name().left(7).toUpper() == "MAILTO:" ) { 00368 a->setName( a->name().remove( 0, 7 ) ); 00369 } 00370 00371 d->mAttendees.append( a ); 00372 if ( doupdate ) { 00373 updated(); 00374 } 00375 } 00376 00377 const Attendee::List &IncidenceBase::attendees() const 00378 { 00379 return d->mAttendees; 00380 } 00381 00382 int IncidenceBase::attendeeCount() const 00383 { 00384 return d->mAttendees.count(); 00385 } 00386 00387 void IncidenceBase::clearAttendees() 00388 { 00389 if ( mReadOnly ) { 00390 return; 00391 } 00392 qDeleteAll( d->mAttendees ); 00393 d->mAttendees.clear(); 00394 } 00395 00396 Attendee *IncidenceBase::attendeeByMail( const QString &email ) const 00397 { 00398 Attendee::List::ConstIterator it; 00399 for ( it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it ) { 00400 if ( (*it)->email() == email ) { 00401 return *it; 00402 } 00403 } 00404 00405 return 0; 00406 } 00407 00408 Attendee *IncidenceBase::attendeeByMails( const QStringList &emails, 00409 const QString &email ) const 00410 { 00411 QStringList mails = emails; 00412 if ( !email.isEmpty() ) { 00413 mails.append( email ); 00414 } 00415 00416 Attendee::List::ConstIterator itA; 00417 for ( itA = d->mAttendees.constBegin(); itA != d->mAttendees.constEnd(); ++itA ) { 00418 for ( QStringList::const_iterator it = mails.constBegin(); it != mails.constEnd(); ++it ) { 00419 if ( (*itA)->email() == (*it) ) { 00420 return *itA; 00421 } 00422 } 00423 } 00424 00425 return 0; 00426 } 00427 00428 Attendee *IncidenceBase::attendeeByUid( const QString &uid ) const 00429 { 00430 Attendee::List::ConstIterator it; 00431 for ( it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it ) { 00432 if ( (*it)->uid() == uid ) { 00433 return *it; 00434 } 00435 } 00436 00437 return 0; 00438 } 00439 00440 void IncidenceBase::setDuration( const Duration &duration ) 00441 { 00442 d->mDuration = duration; 00443 setHasDuration( true ); 00444 updated(); 00445 } 00446 00447 Duration IncidenceBase::duration() const 00448 { 00449 return d->mDuration; 00450 } 00451 00452 void IncidenceBase::setHasDuration( bool hasDuration ) 00453 { 00454 d->mHasDuration = hasDuration; 00455 } 00456 00457 bool IncidenceBase::hasDuration() const 00458 { 00459 return d->mHasDuration; 00460 } 00461 00462 void IncidenceBase::registerObserver( IncidenceBase::IncidenceObserver *observer ) 00463 { 00464 if ( !d->mObservers.contains( observer ) ) { 00465 d->mObservers.append( observer ); 00466 } 00467 } 00468 00469 void IncidenceBase::unRegisterObserver( IncidenceBase::IncidenceObserver *observer ) 00470 { 00471 d->mObservers.removeAll( observer ); 00472 } 00473 00474 void IncidenceBase::updated() 00475 { 00476 if ( d->mUpdateGroupLevel ) { 00477 d->mUpdatedPending = true; 00478 } else { 00479 foreach ( IncidenceObserver *o, d->mObservers ) { 00480 if ( o ) { 00481 o->incidenceUpdated( this ); 00482 } 00483 } 00484 } 00485 } 00486 00487 void IncidenceBase::startUpdates() 00488 { 00489 ++d->mUpdateGroupLevel; 00490 } 00491 00492 void IncidenceBase::endUpdates() 00493 { 00494 if ( d->mUpdateGroupLevel > 0 ) { 00495 if ( --d->mUpdateGroupLevel == 0 && d->mUpdatedPending ) { 00496 d->mUpdatedPending = false; 00497 updated(); 00498 } 00499 } 00500 } 00501 00502 void IncidenceBase::customPropertyUpdated() 00503 { 00504 updated(); 00505 } 00506 00507 KUrl IncidenceBase::uri() const 00508 { 00509 return KUrl( QString( "urn:x-ical:" ) + uid() ); 00510 } 00511 00512 bool IncidenceBase::Visitor::visit( Event *event ) 00513 { 00514 Q_UNUSED( event ); 00515 return false; 00516 } 00517 00518 bool IncidenceBase::Visitor::visit( Todo *todo ) 00519 { 00520 Q_UNUSED( todo ); 00521 return false; 00522 } 00523 00524 bool IncidenceBase::Visitor::visit( Journal *journal ) 00525 { 00526 Q_UNUSED( journal ); 00527 return false; 00528 } 00529 00530 bool IncidenceBase::Visitor::visit( FreeBusy *freebusy ) 00531 { 00532 Q_UNUSED( freebusy ); 00533 return false; 00534 }