KCalCore Library
freebusy.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the kcalcore library. 00003 00004 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 00005 Copyright (C) 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 */ 00033 #include "freebusy.h" 00034 #include "visitor.h" 00035 00036 #include "icalformat.h" 00037 00038 #include <KDebug> 00039 00040 using namespace KCalCore; 00041 00042 //@cond PRIVATE 00043 class KCalCore::FreeBusy::Private 00044 { 00045 private: 00046 FreeBusy *q; 00047 public: 00048 Private( FreeBusy *qq ) : q( qq ) 00049 {} 00050 00051 Private( const KCalCore::FreeBusy::Private &other, FreeBusy *qq ) : q( qq ) 00052 { 00053 init( other ); 00054 } 00055 00056 Private( const FreeBusyPeriod::List &busyPeriods, FreeBusy *qq ) 00057 : q( qq ), mBusyPeriods( busyPeriods ) 00058 {} 00059 00060 void init( const KCalCore::FreeBusy::Private &other ); 00061 void init( const Event::List &events, const KDateTime &start, const KDateTime &end ); 00062 00063 KDateTime mDtEnd; // end datetime 00064 FreeBusyPeriod::List mBusyPeriods; // list of periods 00065 00066 // This is used for creating a freebusy object for the current user 00067 bool addLocalPeriod( FreeBusy *fb, const KDateTime &start, const KDateTime &end ); 00068 }; 00069 00070 void KCalCore::FreeBusy::Private::init( const KCalCore::FreeBusy::Private &other ) 00071 { 00072 mDtEnd = other.mDtEnd; 00073 mBusyPeriods = other.mBusyPeriods; 00074 } 00075 //@endcond 00076 00077 FreeBusy::FreeBusy() 00078 : d( new KCalCore::FreeBusy::Private( this ) ) 00079 { 00080 } 00081 00082 FreeBusy::FreeBusy( const FreeBusy &other ) 00083 : IncidenceBase( other ), 00084 d( new KCalCore::FreeBusy::Private( *other.d, this ) ) 00085 { 00086 } 00087 00088 FreeBusy::FreeBusy( const KDateTime &start, const KDateTime &end ) 00089 : d( new KCalCore::FreeBusy::Private( this ) ) 00090 { 00091 setDtStart( start ); 00092 setDtEnd( end ); 00093 } 00094 00095 FreeBusy::FreeBusy( const Event::List &events, const KDateTime &start, const KDateTime &end ) 00096 : d( new KCalCore::FreeBusy::Private( this ) ) 00097 { 00098 setDtStart( start ); 00099 setDtEnd( end ); 00100 00101 d->init( events, start, end ); 00102 } 00103 00104 //@cond PRIVATE 00105 void FreeBusy::Private::init( const Event::List &eventList, 00106 const KDateTime &start, const KDateTime &end ) 00107 { 00108 int extraDays, i, x, duration; 00109 duration = start.daysTo( end ); 00110 QDate day; 00111 KDateTime tmpStart; 00112 KDateTime tmpEnd; 00113 00114 // Loops through every event in the calendar 00115 Event::List::ConstIterator it; 00116 for ( it = eventList.constBegin(); it != eventList.constEnd(); ++it ) { 00117 Event::Ptr event = *it; 00118 00119 // If this event is transparent it shouldn't be in the freebusy list. 00120 if ( event->transparency() == Event::Transparent ) { 00121 continue; 00122 } 00123 00124 // The code below can not handle all-day events. Fixing this resulted 00125 // in a lot of duplicated code. Instead, make a copy of the event and 00126 // set the period to the full day(s). This trick works for recurring, 00127 // multiday, and single day all-day events. 00128 Event::Ptr allDayEvent; 00129 if ( event->allDay() ) { 00130 // addDay event. Do the hack 00131 kDebug() << "All-day event"; 00132 allDayEvent = Event::Ptr( new Event( *event ) ); 00133 00134 // Set the start and end times to be on midnight 00135 KDateTime st = allDayEvent->dtStart(); 00136 st.setTime( QTime( 0, 0 ) ); 00137 KDateTime nd = allDayEvent->dtEnd(); 00138 nd.setTime( QTime( 23, 59, 59, 999 ) ); 00139 allDayEvent->setAllDay( false ); 00140 allDayEvent->setDtStart( st ); 00141 allDayEvent->setDtEnd( nd ); 00142 00143 kDebug() << "Use:" << st.toString() << "to" << nd.toString(); 00144 // Finally, use this event for the setting below 00145 event = allDayEvent; 00146 } 00147 00148 // This whole for loop is for recurring events, it loops through 00149 // each of the days of the freebusy request 00150 00151 for ( i = 0; i <= duration; ++i ) { 00152 day = start.addDays(i).date(); 00153 tmpStart.setDate( day ); 00154 tmpEnd.setDate( day ); 00155 00156 if ( event->recurs() ) { 00157 if ( event->isMultiDay() ) { 00158 // FIXME: This doesn't work for sub-daily recurrences or recurrences with 00159 // a different time than the original event. 00160 extraDays = event->dtStart().daysTo( event->dtEnd() ); 00161 for ( x = 0; x <= extraDays; ++x ) { 00162 if ( event->recursOn( day.addDays(-x), start.timeSpec() ) ) { 00163 tmpStart.setDate( day.addDays(-x) ); 00164 tmpStart.setTime( event->dtStart().time() ); 00165 tmpEnd = event->duration().end( tmpStart ); 00166 00167 addLocalPeriod( q, tmpStart, tmpEnd ); 00168 break; 00169 } 00170 } 00171 } else { 00172 if ( event->recursOn( day, start.timeSpec() ) ) { 00173 tmpStart.setTime( event->dtStart().time() ); 00174 tmpEnd.setTime( event->dtEnd().time() ); 00175 00176 addLocalPeriod ( q, tmpStart, tmpEnd ); 00177 } 00178 } 00179 } 00180 00181 } 00182 // Non-recurring events 00183 addLocalPeriod( q, event->dtStart(), event->dtEnd() ); 00184 } 00185 00186 q->sortList(); 00187 } 00188 //@endcond 00189 00190 FreeBusy::FreeBusy( const Period::List &busyPeriods ) 00191 : d( new KCalCore::FreeBusy::Private( this ) ) 00192 { 00193 addPeriods(busyPeriods); 00194 } 00195 00196 FreeBusy::FreeBusy( const FreeBusyPeriod::List &busyPeriods ) 00197 : d( new KCalCore::FreeBusy::Private( busyPeriods, this ) ) 00198 { 00199 } 00200 00201 FreeBusy::~FreeBusy() 00202 { 00203 delete d; 00204 } 00205 00206 IncidenceBase::IncidenceType FreeBusy::type() const 00207 { 00208 return TypeFreeBusy; 00209 } 00210 00211 QByteArray FreeBusy::typeStr() const 00212 { 00213 return "FreeBusy"; 00214 } 00215 00216 void FreeBusy::setDtStart( const KDateTime &start ) 00217 { 00218 IncidenceBase::setDtStart( start.toUtc() ); 00219 updated(); 00220 } 00221 00222 void FreeBusy::setDtEnd( const KDateTime &end ) 00223 { 00224 d->mDtEnd = end; 00225 } 00226 00227 KDateTime FreeBusy::dtEnd() const 00228 { 00229 return d->mDtEnd; 00230 } 00231 00232 Period::List FreeBusy::busyPeriods() const 00233 { 00234 Period::List res; 00235 00236 foreach ( const FreeBusyPeriod &p, d->mBusyPeriods ) { 00237 res << p; 00238 } 00239 00240 return res; 00241 } 00242 00243 FreeBusyPeriod::List FreeBusy::fullBusyPeriods() const 00244 { 00245 return d->mBusyPeriods; 00246 } 00247 00248 void FreeBusy::sortList() 00249 { 00250 qSort( d->mBusyPeriods ); 00251 return; 00252 } 00253 00254 void FreeBusy::addPeriods( const Period::List &list ) 00255 { 00256 foreach ( const Period &p, list ) { 00257 d->mBusyPeriods << FreeBusyPeriod( p ); 00258 } 00259 sortList(); 00260 } 00261 00262 void FreeBusy::addPeriods( const FreeBusyPeriod::List &list ) 00263 { 00264 d->mBusyPeriods += list; 00265 sortList(); 00266 } 00267 00268 void FreeBusy::addPeriod( const KDateTime &start, const KDateTime &end ) 00269 { 00270 d->mBusyPeriods.append( FreeBusyPeriod( start, end ) ); 00271 sortList(); 00272 } 00273 00274 void FreeBusy::addPeriod( const KDateTime &start, const Duration &duration ) 00275 { 00276 d->mBusyPeriods.append( FreeBusyPeriod( start, duration ) ); 00277 sortList(); 00278 } 00279 00280 void FreeBusy::merge( FreeBusy::Ptr freeBusy ) 00281 { 00282 if ( freeBusy->dtStart() < dtStart() ) { 00283 setDtStart( freeBusy->dtStart() ); 00284 } 00285 00286 if ( freeBusy->dtEnd() > dtEnd() ) { 00287 setDtEnd( freeBusy->dtEnd() ); 00288 } 00289 00290 Period::List periods = freeBusy->busyPeriods(); 00291 Period::List::ConstIterator it; 00292 for ( it = periods.constBegin(); it != periods.constEnd(); ++it ) { 00293 d->mBusyPeriods.append( FreeBusyPeriod( (*it).start(), (*it).end() ) ); 00294 } 00295 sortList(); 00296 } 00297 00298 void FreeBusy::shiftTimes( const KDateTime::Spec &oldSpec, 00299 const KDateTime::Spec &newSpec ) 00300 { 00301 if ( oldSpec.isValid() && newSpec.isValid() && oldSpec != newSpec ) { 00302 IncidenceBase::shiftTimes( oldSpec, newSpec ); 00303 d->mDtEnd = d->mDtEnd.toTimeSpec( oldSpec ); 00304 d->mDtEnd.setTimeSpec( newSpec ); 00305 foreach ( FreeBusyPeriod p, d->mBusyPeriods ) { //krazy:exclude=foreach 00306 p.shiftTimes( oldSpec, newSpec ); 00307 } 00308 } 00309 } 00310 00311 IncidenceBase &FreeBusy::assign( const IncidenceBase &other ) 00312 { 00313 if ( &other != this ) { 00314 IncidenceBase::assign( other ); 00315 const FreeBusy *f = static_cast<const FreeBusy*>( &other ); 00316 d->init( *( f->d ) ); 00317 } 00318 return *this; 00319 } 00320 00321 bool FreeBusy::equals( const IncidenceBase &freeBusy ) const 00322 { 00323 if ( !IncidenceBase::equals( freeBusy ) ) { 00324 return false; 00325 } else { 00326 // If they weren't the same type IncidenceBase::equals would had returned false already 00327 const FreeBusy *fb = static_cast<const FreeBusy*>( &freeBusy ); 00328 return 00329 dtEnd() == fb->dtEnd() && 00330 d->mBusyPeriods == fb->d->mBusyPeriods; 00331 } 00332 } 00333 00334 bool FreeBusy::accept( Visitor &v, IncidenceBase::Ptr incidence ) 00335 { 00336 return v.visit( incidence.staticCast<FreeBusy>() ); 00337 } 00338 00339 KDateTime FreeBusy::dateTime( DateTimeRole role ) const 00340 { 00341 Q_UNUSED( role ); 00342 // No roles affecting freeBusy yet 00343 return KDateTime(); 00344 } 00345 00346 void FreeBusy::setDateTime( const KDateTime &dateTime, DateTimeRole role ) 00347 { 00348 Q_UNUSED( dateTime ); 00349 Q_UNUSED( role ); 00350 } 00351 00352 void FreeBusy::virtual_hook( int id, void *data ) 00353 { 00354 Q_UNUSED( id ); 00355 Q_UNUSED( data ); 00356 Q_ASSERT( false ); 00357 } 00358 00359 //@cond PRIVATE 00360 bool FreeBusy::Private::addLocalPeriod( FreeBusy *fb, 00361 const KDateTime &eventStart, 00362 const KDateTime &eventEnd ) 00363 { 00364 KDateTime tmpStart; 00365 KDateTime tmpEnd; 00366 00367 //Check to see if the start *or* end of the event is 00368 //between the start and end of the freebusy dates. 00369 KDateTime start = fb->dtStart(); 00370 if ( !( ( ( start.secsTo( eventStart ) >= 0 ) && 00371 ( eventStart.secsTo( mDtEnd ) >= 0 ) ) || 00372 ( ( start.secsTo( eventEnd ) >= 0 ) && 00373 ( eventEnd.secsTo( mDtEnd ) >= 0 ) ) ) ) { 00374 return false; 00375 } 00376 00377 if ( eventStart.secsTo( start ) >= 0 ) { 00378 tmpStart = start; 00379 } else { 00380 tmpStart = eventStart; 00381 } 00382 00383 if ( eventEnd.secsTo( mDtEnd ) <= 0 ) { 00384 tmpEnd = mDtEnd; 00385 } else { 00386 tmpEnd = eventEnd; 00387 } 00388 00389 FreeBusyPeriod p( tmpStart, tmpEnd ); 00390 mBusyPeriods.append( p ); 00391 00392 return true; 00393 } 00394 //@endcond 00395 00396 QLatin1String FreeBusy::mimeType() const 00397 { 00398 return FreeBusy::freeBusyMimeType(); 00399 } 00400 00401 QLatin1String KCalCore::FreeBusy::freeBusyMimeType() 00402 { 00403 return QLatin1String( "application/x-vnd.akonadi.calendar.freebusy" ); 00404 } 00405 00406 QDataStream &KCalCore::operator<<( QDataStream &stream, const KCalCore::FreeBusy::Ptr &freebusy ) 00407 { 00408 KCalCore::ICalFormat format; 00409 QString data = format.createScheduleMessage( freebusy, iTIPPublish ); 00410 return stream << data; 00411 } 00412 00413 QDataStream &KCalCore::operator>>( QDataStream &stream, KCalCore::FreeBusy::Ptr &freebusy ) 00414 { 00415 QString freeBusyVCal; 00416 stream >> freeBusyVCal; 00417 00418 KCalCore::ICalFormat format; 00419 freebusy = format.parseFreeBusy( freeBusyVCal ); 00420 00421 if ( !freebusy ) { 00422 kDebug() << "Error parsing free/busy"; 00423 kDebug() << freeBusyVCal; 00424 } 00425 00426 return stream; 00427 } 00428
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu Aug 2 2012 15:24:11 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu Aug 2 2012 15:24:11 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.