00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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;
00064 FreeBusyPeriod::List mBusyPeriods;
00065
00066
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
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
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
00115 Event::List::ConstIterator it;
00116 for ( it = eventList.constBegin(); it != eventList.constEnd(); ++it ) {
00117 Event::Ptr event = *it;
00118
00119
00120 if ( event->transparency() == Event::Transparent ) {
00121 continue;
00122 }
00123
00124
00125
00126
00127
00128 Event::Ptr allDayEvent;
00129 if ( event->allDay() ) {
00130
00131 kDebug() << "All-day event";
00132 allDayEvent = Event::Ptr( new Event( *event ) );
00133
00134
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
00145 event = allDayEvent;
00146 }
00147
00148
00149
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
00159
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
00183 addLocalPeriod( q, event->dtStart(), event->dtEnd() );
00184 }
00185
00186 q->sortList();
00187 }
00188
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 ) {
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
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
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
00360 bool FreeBusy::Private::addLocalPeriod( FreeBusy *fb,
00361 const KDateTime &eventStart,
00362 const KDateTime &eventEnd )
00363 {
00364 KDateTime tmpStart;
00365 KDateTime tmpEnd;
00366
00367
00368
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
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