incidence.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) 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 "incidence.h" 00036 #include "calformat.h" 00037 00038 #include <KMimeType> 00039 #include <KTemporaryFile> 00040 00041 #include <QtGui/QTextDocument> // for Qt::escape() and Qt::mightBeRichText() 00042 00043 using namespace KCalCore; 00044 00049 //@cond PRIVATE 00050 class KCalCore::Incidence::Private 00051 { 00052 public: 00053 Private() 00054 : mRevision( 0 ), 00055 mDescriptionIsRich( false ), 00056 mSummaryIsRich( false ), 00057 mLocationIsRich( false ), 00058 mRecurrence( 0 ), 00059 mStatus( StatusNone ), 00060 mSecrecy( SecrecyPublic ), 00061 mPriority( 0 ), 00062 mGeoLatitude( INVALID_LATLON ), 00063 mGeoLongitude( INVALID_LATLON ), 00064 mHasGeo( false ), 00065 mLocalOnly( false ) 00066 { 00067 } 00068 00069 Private( const Private &p ) 00070 : mCreated( p.mCreated ), 00071 mRevision( p.mRevision ), 00072 mDescription( p.mDescription ), 00073 mDescriptionIsRich( p.mDescriptionIsRich ), 00074 mSummary( p.mSummary ), 00075 mSummaryIsRich( p.mSummaryIsRich ), 00076 mLocation( p.mLocation ), 00077 mLocationIsRich( p.mLocationIsRich ), 00078 mCategories( p.mCategories ), 00079 mRecurrence ( 0 ), 00080 mResources( p.mResources ), 00081 mStatus( p.mStatus ), 00082 mStatusString( p.mStatusString ), 00083 mSecrecy( p.mSecrecy ), 00084 mPriority( p.mPriority ), 00085 mSchedulingID( p.mSchedulingID ), 00086 mRelatedToUid( p.mRelatedToUid ), 00087 mGeoLatitude( p.mGeoLatitude ), 00088 mGeoLongitude( p.mGeoLongitude ), 00089 mHasGeo( p.mHasGeo ), 00090 mRecurrenceId( p.mRecurrenceId ), 00091 mLocalOnly( false ) 00092 { 00093 } 00094 00095 void clear() 00096 { 00097 mAlarms.clear(); 00098 mAttachments.clear(); 00099 delete mRecurrence; 00100 mRecurrence = 0; 00101 } 00102 00103 void init( Incidence *dest, const Incidence &src ) 00104 { 00105 mRevision = src.d->mRevision; 00106 mCreated = src.d->mCreated; 00107 mDescription = src.d->mDescription; 00108 mSummary = src.d->mSummary; 00109 mCategories = src.d->mCategories; 00110 mRelatedToUid = src.d->mRelatedToUid; 00111 mResources = src.d->mResources; 00112 mStatusString = src.d->mStatusString; 00113 mStatus = src.d->mStatus; 00114 mSecrecy = src.d->mSecrecy; 00115 mPriority = src.d->mPriority; 00116 mLocation = src.d->mLocation; 00117 mGeoLatitude = src.d->mGeoLatitude; 00118 mGeoLongitude = src.d->mGeoLongitude; 00119 mHasGeo = src.d->mHasGeo; 00120 mRecurrenceId = src.d->mRecurrenceId; 00121 mLocalOnly = src.d->mLocalOnly; 00122 00123 // Alarms and Attachments are stored in ListBase<...>, which is a QValueList<...*>. 00124 // We need to really duplicate the objects stored therein, otherwise deleting 00125 // i will also delete all attachments from this object (setAutoDelete...) 00126 foreach ( Alarm::Ptr alarm, src.d->mAlarms ) { 00127 Alarm::Ptr b ( new Alarm( *alarm.data() ) ); 00128 b->setParent( dest ); 00129 mAlarms.append( b ); 00130 } 00131 00132 foreach ( Attachment::Ptr attachment, src.d->mAttachments ) { 00133 Attachment::Ptr a( new Attachment( *attachment ) ); 00134 mAttachments.append( a ); 00135 } 00136 00137 if ( src.d->mRecurrence ) { 00138 mRecurrence = new Recurrence( *( src.d->mRecurrence ) ); 00139 mRecurrence->addObserver( dest ); 00140 } else { 00141 mRecurrence = 0; 00142 } 00143 } 00144 00145 KDateTime mCreated; // creation datetime 00146 int mRevision; // revision number 00147 00148 QString mDescription; // description string 00149 bool mDescriptionIsRich; // description string is richtext. 00150 QString mSummary; // summary string 00151 bool mSummaryIsRich; // summary string is richtext. 00152 QString mLocation; // location string 00153 bool mLocationIsRich; // location string is richtext. 00154 QStringList mCategories; // category list 00155 mutable Recurrence *mRecurrence; // recurrence 00156 Attachment::List mAttachments; // attachments list 00157 Alarm::List mAlarms; // alarms list 00158 QStringList mResources; // resources list (not calendar resources) 00159 Status mStatus; // status 00160 QString mStatusString; // status string, for custom status 00161 Secrecy mSecrecy; // secrecy 00162 int mPriority; // priority: 1 = highest, 2 = less, etc. 00163 QString mSchedulingID; // ID for scheduling mails 00164 00165 QMap<RelType,QString> mRelatedToUid;// incidence uid this is related to, for each relType 00166 float mGeoLatitude; // Specifies latitude in decimal degrees 00167 float mGeoLongitude; // Specifies longitude in decimal degrees 00168 bool mHasGeo; // if incidence has geo data 00169 QHash<Attachment::Ptr,QString> mTempFiles; // Temporary files for writing attachments to. 00170 KDateTime mRecurrenceId; // recurrenceId 00171 bool mLocalOnly; // allow changes that won't go to the server 00172 }; 00173 //@endcond 00174 00175 Incidence::Incidence() 00176 : IncidenceBase(), d( new KCalCore::Incidence::Private ) 00177 { 00178 recreate(); 00179 resetDirtyFields(); 00180 } 00181 00182 Incidence::Incidence( const Incidence &i ) 00183 : IncidenceBase( i ), 00184 Recurrence::RecurrenceObserver(), 00185 d( new KCalCore::Incidence::Private( *i.d ) ) 00186 { 00187 d->init( this, i ); 00188 resetDirtyFields(); 00189 } 00190 00191 Incidence::~Incidence() 00192 { 00193 // Alarm has a raw incidence pointer, so we must set it to 0 00194 // so Alarm doesn't use it after Incidence is destroyed 00195 foreach ( Alarm::Ptr alarm, d->mAlarms ) { 00196 alarm->setParent( 0 ); 00197 } 00198 00199 delete d->mRecurrence; 00200 delete d; 00201 } 00202 00203 //@cond PRIVATE 00204 // A string comparison that considers that null and empty are the same 00205 static bool stringCompare( const QString &s1, const QString &s2 ) 00206 { 00207 return ( s1.isEmpty() && s2.isEmpty() ) || ( s1 == s2 ); 00208 } 00209 00210 //@endcond 00211 IncidenceBase &Incidence::assign( const IncidenceBase &other ) 00212 { 00213 if ( &other != this ) { 00214 d->clear(); 00215 //TODO: should relations be cleared out, as in destructor??? 00216 IncidenceBase::assign( other ); 00217 const Incidence *i = static_cast<const Incidence*>( &other ); 00218 d->init( this, *i ); 00219 } 00220 00221 return *this; 00222 } 00223 00224 bool Incidence::equals( const IncidenceBase &incidence ) const 00225 { 00226 if ( !IncidenceBase::equals( incidence ) ) { 00227 return false; 00228 } 00229 00230 // If they weren't the same type IncidenceBase::equals would had returned false already 00231 const Incidence *i2 = static_cast<const Incidence *>( &incidence ); 00232 00233 if ( alarms().count() != i2->alarms().count() ) { 00234 return false; 00235 } 00236 00237 Alarm::List::ConstIterator a1 = alarms().constBegin(); 00238 Alarm::List::ConstIterator a1end = alarms().constEnd(); 00239 Alarm::List::ConstIterator a2 = i2->alarms().constBegin(); 00240 Alarm::List::ConstIterator a2end = i2->alarms().constEnd(); 00241 for ( ; a1 != a1end && a2 != a2end; ++a1, ++a2 ) { 00242 if ( **a1 == **a2 ) { 00243 continue; 00244 } else { 00245 return false; 00246 } 00247 } 00248 00249 if ( attachments().count() != i2->attachments().count() ) { 00250 return false; 00251 } 00252 00253 Attachment::List::ConstIterator att1 = attachments().constBegin(); 00254 const Attachment::List::ConstIterator att1end = attachments().constEnd(); 00255 Attachment::List::ConstIterator att2 = i2->attachments().constBegin(); 00256 const Attachment::List::ConstIterator att2end = i2->attachments().constEnd(); 00257 for ( ; att1 != att1end && att2 != att2end; ++att1, ++att2 ) { 00258 if ( **att1 == **att2 ) { 00259 continue; 00260 } else { 00261 return false; 00262 } 00263 } 00264 00265 bool recurrenceEqual = ( d->mRecurrence == 0 && i2->d->mRecurrence == 0 ); 00266 if ( !recurrenceEqual ) { 00267 recurrence(); // create if doesn't exist 00268 i2->recurrence(); // create if doesn't exist 00269 recurrenceEqual = d->mRecurrence != 0 && 00270 i2->d->mRecurrence != 0 && 00271 *d->mRecurrence == *i2->d->mRecurrence; 00272 } 00273 00274 return 00275 recurrenceEqual && 00276 created() == i2->created() && 00277 stringCompare( description(), i2->description() ) && 00278 stringCompare( summary(), i2->summary() ) && 00279 categories() == i2->categories() && 00280 stringCompare( relatedTo(), i2->relatedTo() ) && 00281 resources() == i2->resources() && 00282 d->mStatus == i2->d->mStatus && 00283 ( d->mStatus == StatusNone || 00284 stringCompare( d->mStatusString, i2->d->mStatusString ) ) && 00285 secrecy() == i2->secrecy() && 00286 priority() == i2->priority() && 00287 stringCompare( location(), i2->location() ) && 00288 stringCompare( schedulingID(), i2->schedulingID() ); 00289 } 00290 00291 void Incidence::recreate() 00292 { 00293 const KDateTime nowUTC = KDateTime::currentUtcDateTime(); 00294 setCreated( nowUTC ); 00295 00296 setSchedulingID( QString(), CalFormat::createUniqueId() ); 00297 setRevision( 0 ); 00298 setLastModified( nowUTC ); 00299 } 00300 00301 void Incidence::setLastModified( const KDateTime &lm ) 00302 { 00303 if ( !d->mLocalOnly ) { 00304 IncidenceBase::setLastModified( lm ); 00305 } 00306 } 00307 00308 void Incidence::setReadOnly( bool readOnly ) 00309 { 00310 IncidenceBase::setReadOnly( readOnly ); 00311 if ( d->mRecurrence ) { 00312 d->mRecurrence->setRecurReadOnly( readOnly ); 00313 } 00314 } 00315 00316 void Incidence::setLocalOnly( bool localOnly ) 00317 { 00318 if ( mReadOnly ) { 00319 return; 00320 } 00321 d->mLocalOnly = localOnly; 00322 } 00323 00324 bool Incidence::localOnly() const 00325 { 00326 return d->mLocalOnly; 00327 } 00328 00329 void Incidence::setAllDay( bool allDay ) 00330 { 00331 if ( mReadOnly ) { 00332 return; 00333 } 00334 if ( d->mRecurrence ) { 00335 d->mRecurrence->setAllDay( allDay ); 00336 } 00337 IncidenceBase::setAllDay( allDay ); 00338 } 00339 00340 void Incidence::setCreated( const KDateTime &created ) 00341 { 00342 if ( mReadOnly || d->mLocalOnly ) { 00343 return; 00344 } 00345 00346 d->mCreated = created.toUtc(); 00347 setFieldDirty( FieldCreated ); 00348 00349 // FIXME: Shouldn't we call updated for the creation date, too? 00350 // updated(); 00351 } 00352 00353 KDateTime Incidence::created() const 00354 { 00355 return d->mCreated; 00356 } 00357 00358 void Incidence::setRevision( int rev ) 00359 { 00360 if ( mReadOnly || d->mLocalOnly ) { 00361 return; 00362 } 00363 00364 update(); 00365 00366 d->mRevision = rev; 00367 setFieldDirty( FieldRevision ); 00368 updated(); 00369 } 00370 00371 int Incidence::revision() const 00372 { 00373 return d->mRevision; 00374 } 00375 00376 void Incidence::setDtStart( const KDateTime &dt ) 00377 { 00378 if ( d->mRecurrence ) { 00379 d->mRecurrence->setStartDateTime( dt ); 00380 d->mRecurrence->setAllDay( allDay() ); 00381 } 00382 IncidenceBase::setDtStart( dt ); 00383 } 00384 00385 void Incidence::shiftTimes( const KDateTime::Spec &oldSpec, 00386 const KDateTime::Spec &newSpec ) 00387 { 00388 IncidenceBase::shiftTimes( oldSpec, newSpec ); 00389 if ( d->mRecurrence ) { 00390 d->mRecurrence->shiftTimes( oldSpec, newSpec ); 00391 } 00392 for ( int i = 0, end = d->mAlarms.count(); i < end; ++i ) { 00393 d->mAlarms[i]->shiftTimes( oldSpec, newSpec ); 00394 } 00395 } 00396 00397 void Incidence::setDescription( const QString &description, bool isRich ) 00398 { 00399 if ( mReadOnly ) { 00400 return; 00401 } 00402 update(); 00403 d->mDescription = description; 00404 d->mDescriptionIsRich = isRich; 00405 setFieldDirty( FieldDescription ); 00406 updated(); 00407 } 00408 00409 void Incidence::setDescription( const QString &description ) 00410 { 00411 setDescription( description, Qt::mightBeRichText( description ) ); 00412 } 00413 00414 QString Incidence::description() const 00415 { 00416 return d->mDescription; 00417 } 00418 00419 QString Incidence::richDescription() const 00420 { 00421 if ( descriptionIsRich() ) { 00422 return d->mDescription; 00423 } else { 00424 return Qt::escape( d->mDescription ).replace( '\n', "<br/>" ); 00425 } 00426 } 00427 00428 bool Incidence::descriptionIsRich() const 00429 { 00430 return d->mDescriptionIsRich; 00431 } 00432 00433 void Incidence::setSummary( const QString &summary, bool isRich ) 00434 { 00435 if ( mReadOnly ) { 00436 return; 00437 } 00438 update(); 00439 d->mSummary = summary; 00440 d->mSummaryIsRich = isRich; 00441 setFieldDirty( FieldSummary ); 00442 updated(); 00443 } 00444 00445 void Incidence::setSummary( const QString &summary ) 00446 { 00447 setSummary( summary, Qt::mightBeRichText( summary ) ); 00448 } 00449 00450 QString Incidence::summary() const 00451 { 00452 return d->mSummary; 00453 } 00454 00455 QString Incidence::richSummary() const 00456 { 00457 if ( summaryIsRich() ) { 00458 return d->mSummary; 00459 } else { 00460 return Qt::escape( d->mSummary ).replace( '\n', "<br/>" ); 00461 } 00462 } 00463 00464 bool Incidence::summaryIsRich() const 00465 { 00466 return d->mSummaryIsRich; 00467 } 00468 00469 void Incidence::setCategories( const QStringList &categories ) 00470 { 00471 if ( mReadOnly ) { 00472 return; 00473 } 00474 00475 update(); 00476 d->mCategories = categories; 00477 updated(); 00478 } 00479 00480 void Incidence::setCategories( const QString &catStr ) 00481 { 00482 if ( mReadOnly ) { 00483 return; 00484 } 00485 update(); 00486 setFieldDirty( FieldCategories ); 00487 00488 d->mCategories.clear(); 00489 00490 if ( catStr.isEmpty() ) { 00491 updated(); 00492 return; 00493 } 00494 00495 d->mCategories = catStr.split( ',' ); 00496 00497 QStringList::Iterator it; 00498 for ( it = d->mCategories.begin();it != d->mCategories.end(); ++it ) { 00499 *it = (*it).trimmed(); 00500 } 00501 00502 updated(); 00503 } 00504 00505 QStringList Incidence::categories() const 00506 { 00507 return d->mCategories; 00508 } 00509 00510 QString Incidence::categoriesStr() const 00511 { 00512 return d->mCategories.join( "," ); 00513 } 00514 00515 void Incidence::setRelatedTo( const QString &relatedToUid, RelType relType ) 00516 { 00517 // TODO: RFC says that an incidence can have more than one related-to field 00518 // even for the same relType. 00519 00520 if ( d->mRelatedToUid[relType] != relatedToUid ) { 00521 update(); 00522 d->mRelatedToUid[relType] = relatedToUid; 00523 setFieldDirty( FieldRelatedTo ); 00524 updated(); 00525 } 00526 } 00527 00528 QString Incidence::relatedTo( RelType relType ) const 00529 { 00530 return d->mRelatedToUid.value( relType ); 00531 } 00532 00533 // %%%%%%%%%%%% Recurrence-related methods %%%%%%%%%%%%%%%%%%%% 00534 00535 Recurrence *Incidence::recurrence() const 00536 { 00537 if ( !d->mRecurrence ) { 00538 d->mRecurrence = new Recurrence(); 00539 d->mRecurrence->setStartDateTime( IncidenceBase::dtStart() ); 00540 d->mRecurrence->setAllDay( allDay() ); 00541 d->mRecurrence->setRecurReadOnly( mReadOnly ); 00542 d->mRecurrence->addObserver( const_cast<KCalCore::Incidence*>( this ) ); 00543 } 00544 00545 return d->mRecurrence; 00546 } 00547 00548 void Incidence::clearRecurrence() 00549 { 00550 delete d->mRecurrence; 00551 d->mRecurrence = 0; 00552 } 00553 00554 ushort Incidence::recurrenceType() const 00555 { 00556 if ( d->mRecurrence ) { 00557 return d->mRecurrence->recurrenceType(); 00558 } else { 00559 return Recurrence::rNone; 00560 } 00561 } 00562 00563 bool Incidence::recurs() const 00564 { 00565 if ( d->mRecurrence ) { 00566 return d->mRecurrence->recurs(); 00567 } else { 00568 return false; 00569 } 00570 } 00571 00572 bool Incidence::recursOn( const QDate &date, 00573 const KDateTime::Spec &timeSpec ) const 00574 { 00575 return d->mRecurrence && d->mRecurrence->recursOn( date, timeSpec ); 00576 } 00577 00578 bool Incidence::recursAt( const KDateTime &qdt ) const 00579 { 00580 return d->mRecurrence && d->mRecurrence->recursAt( qdt ); 00581 } 00582 00583 QList<KDateTime> Incidence::startDateTimesForDate( const QDate &date, 00584 const KDateTime::Spec &timeSpec ) const 00585 { 00586 KDateTime start = dtStart(); 00587 KDateTime end = dateTime( RoleEndRecurrenceBase ); 00588 00589 QList<KDateTime> result; 00590 00591 // TODO_Recurrence: Also work if only due date is given... 00592 if ( !start.isValid() && ! end.isValid() ) { 00593 return result; 00594 } 00595 00596 // if the incidence doesn't recur, 00597 KDateTime kdate( date, timeSpec ); 00598 if ( !recurs() ) { 00599 if ( !( start > kdate || end < kdate ) ) { 00600 result << start; 00601 } 00602 return result; 00603 } 00604 00605 int days = start.daysTo( end ); 00606 // Account for possible recurrences going over midnight, while the original event doesn't 00607 QDate tmpday( date.addDays( -days - 1 ) ); 00608 KDateTime tmp; 00609 while ( tmpday <= date ) { 00610 if ( recurrence()->recursOn( tmpday, timeSpec ) ) { 00611 QList<QTime> times = recurrence()->recurTimesOn( tmpday, timeSpec ); 00612 foreach ( const QTime &time, times ) { 00613 tmp = KDateTime( tmpday, time, start.timeSpec() ); 00614 if ( endDateForStart( tmp ) >= kdate ) { 00615 result << tmp; 00616 } 00617 } 00618 } 00619 tmpday = tmpday.addDays( 1 ); 00620 } 00621 return result; 00622 } 00623 00624 QList<KDateTime> Incidence::startDateTimesForDateTime( const KDateTime &datetime ) const 00625 { 00626 KDateTime start = dtStart(); 00627 KDateTime end = dateTime( RoleEndRecurrenceBase ); 00628 00629 QList<KDateTime> result; 00630 00631 // TODO_Recurrence: Also work if only due date is given... 00632 if ( !start.isValid() && ! end.isValid() ) { 00633 return result; 00634 } 00635 00636 // if the incidence doesn't recur, 00637 if ( !recurs() ) { 00638 if ( !( start > datetime || end < datetime ) ) { 00639 result << start; 00640 } 00641 return result; 00642 } 00643 00644 int days = start.daysTo( end ); 00645 // Account for possible recurrences going over midnight, while the original event doesn't 00646 QDate tmpday( datetime.date().addDays( -days - 1 ) ); 00647 KDateTime tmp; 00648 while ( tmpday <= datetime.date() ) { 00649 if ( recurrence()->recursOn( tmpday, datetime.timeSpec() ) ) { 00650 // Get the times during the day (in start date's time zone) when recurrences happen 00651 QList<QTime> times = recurrence()->recurTimesOn( tmpday, start.timeSpec() ); 00652 foreach ( const QTime &time, times ) { 00653 tmp = KDateTime( tmpday, time, start.timeSpec() ); 00654 if ( !( tmp > datetime || endDateForStart( tmp ) < datetime ) ) { 00655 result << tmp; 00656 } 00657 } 00658 } 00659 tmpday = tmpday.addDays( 1 ); 00660 } 00661 return result; 00662 } 00663 00664 KDateTime Incidence::endDateForStart( const KDateTime &startDt ) const 00665 { 00666 KDateTime start = dtStart(); 00667 KDateTime end = dateTime( RoleEndRecurrenceBase ); 00668 if ( !end.isValid() ) { 00669 return start; 00670 } 00671 if ( !start.isValid() ) { 00672 return end; 00673 } 00674 00675 return startDt.addSecs( start.secsTo( end ) ); 00676 } 00677 00678 void Incidence::addAttachment( const Attachment::Ptr &attachment ) 00679 { 00680 if ( mReadOnly || !attachment ) { 00681 return; 00682 } 00683 00684 Q_ASSERT( !d->mAttachments.contains( attachment ) ); 00685 00686 update(); 00687 d->mAttachments.append( attachment ); 00688 setFieldDirty( FieldAttachment ); 00689 updated(); 00690 } 00691 00692 void Incidence::deleteAttachment( const Attachment::Ptr &attachment ) 00693 { 00694 int index = d->mAttachments.indexOf( attachment ); 00695 if ( index > -1 ) { 00696 setFieldDirty( FieldAttachment ); 00697 d->mAttachments.remove( index ); 00698 } 00699 } 00700 00701 void Incidence::deleteAttachments( const QString &mime ) 00702 { 00703 Attachment::List result; 00704 Attachment::List::Iterator it = d->mAttachments.begin(); 00705 while ( it != d->mAttachments.end() ) { 00706 if ( (*it)->mimeType() != mime ) { 00707 result += *it; 00708 } 00709 ++it; 00710 } 00711 d->mAttachments = result; 00712 setFieldDirty( FieldAttachment ); 00713 } 00714 00715 Attachment::List Incidence::attachments() const 00716 { 00717 return d->mAttachments; 00718 } 00719 00720 Attachment::List Incidence::attachments( const QString &mime ) const 00721 { 00722 Attachment::List attachments; 00723 foreach ( Attachment::Ptr attachment, d->mAttachments ) { 00724 if ( attachment->mimeType() == mime ) { 00725 attachments.append( attachment ); 00726 } 00727 } 00728 return attachments; 00729 } 00730 00731 void Incidence::clearAttachments() 00732 { 00733 setFieldDirty( FieldAttachment ); 00734 d->mAttachments.clear(); 00735 } 00736 00737 QString Incidence::writeAttachmentToTempFile( const Attachment::Ptr &attachment ) const 00738 { 00739 if ( d->mTempFiles.contains( attachment ) ) { 00740 return d->mTempFiles.value( attachment ); 00741 } 00742 KTemporaryFile *file = new KTemporaryFile(); 00743 00744 QStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns(); 00745 00746 if ( !patterns.empty() ) { 00747 file->setSuffix( QString( patterns.first() ).remove( '*' ) ); 00748 } 00749 file->setAutoRemove( true ); 00750 file->open(); 00751 // read-only not to give the idea that it could be written to 00752 file->setPermissions( QFile::ReadUser ); 00753 file->write( QByteArray::fromBase64( attachment->data() ) ); 00754 d->mTempFiles.insert( attachment, file->fileName() ); 00755 file->close(); 00756 return d->mTempFiles.value( attachment ); 00757 } 00758 00759 void Incidence::clearTempFiles() 00760 { 00761 QHash<Attachment::Ptr,QString>::const_iterator it = d->mTempFiles.constBegin(); 00762 const QHash<Attachment::Ptr,QString>::const_iterator end = d->mTempFiles.constEnd(); 00763 for ( ; it != end; ++it ) { 00764 QFile::remove( it.value() ); 00765 } 00766 d->mTempFiles.clear(); 00767 } 00768 00769 void Incidence::setResources( const QStringList &resources ) 00770 { 00771 if ( mReadOnly ) { 00772 return; 00773 } 00774 00775 update(); 00776 d->mResources = resources; 00777 setFieldDirty( FieldResources ); 00778 updated(); 00779 } 00780 00781 QStringList Incidence::resources() const 00782 { 00783 return d->mResources; 00784 } 00785 00786 void Incidence::setPriority( int priority ) 00787 { 00788 if ( mReadOnly ) { 00789 return; 00790 } 00791 00792 update(); 00793 d->mPriority = priority; 00794 setFieldDirty( FieldPriority ); 00795 updated(); 00796 } 00797 00798 int Incidence::priority() const 00799 { 00800 return d->mPriority; 00801 } 00802 00803 void Incidence::setStatus( Incidence::Status status ) 00804 { 00805 if ( mReadOnly || status == StatusX ) { 00806 return; 00807 } 00808 00809 update(); 00810 d->mStatus = status; 00811 d->mStatusString.clear(); 00812 setFieldDirty( FieldStatus ); 00813 updated(); 00814 } 00815 00816 void Incidence::setCustomStatus( const QString &status ) 00817 { 00818 if ( mReadOnly ) { 00819 return; 00820 } 00821 00822 update(); 00823 d->mStatus = status.isEmpty() ? StatusNone : StatusX; 00824 d->mStatusString = status; 00825 setFieldDirty( FieldStatus ); 00826 updated(); 00827 } 00828 00829 Incidence::Status Incidence::status() const 00830 { 00831 return d->mStatus; 00832 } 00833 00834 QString Incidence::customStatus() const 00835 { 00836 if ( d->mStatus == StatusX ) { 00837 return d->mStatusString; 00838 } else { 00839 return QString(); 00840 } 00841 } 00842 00843 void Incidence::setSecrecy( Incidence::Secrecy secrecy ) 00844 { 00845 if ( mReadOnly ) { 00846 return; 00847 } 00848 00849 update(); 00850 d->mSecrecy = secrecy; 00851 setFieldDirty( FieldSecrecy ); 00852 updated(); 00853 } 00854 00855 Incidence::Secrecy Incidence::secrecy() const 00856 { 00857 return d->mSecrecy; 00858 } 00859 00860 Alarm::List Incidence::alarms() const 00861 { 00862 return d->mAlarms; 00863 } 00864 00865 Alarm::Ptr Incidence::newAlarm() 00866 { 00867 Alarm::Ptr alarm( new Alarm( this ) ); 00868 d->mAlarms.append( alarm ); 00869 return alarm; 00870 } 00871 00872 void Incidence::addAlarm( const Alarm::Ptr &alarm ) 00873 { 00874 update(); 00875 d->mAlarms.append( alarm ); 00876 setFieldDirty( FieldAlarms ); 00877 updated(); 00878 } 00879 00880 void Incidence::removeAlarm( const Alarm::Ptr &alarm ) 00881 { 00882 const int index = d->mAlarms.indexOf( alarm ); 00883 if ( index > -1 ) { 00884 update(); 00885 d->mAlarms.remove( index ); 00886 setFieldDirty( FieldAlarms ); 00887 updated(); 00888 } 00889 } 00890 00891 void Incidence::clearAlarms() 00892 { 00893 update(); 00894 d->mAlarms.clear(); 00895 setFieldDirty( FieldAlarms ); 00896 updated(); 00897 } 00898 00899 bool Incidence::hasEnabledAlarms() const 00900 { 00901 foreach ( Alarm::Ptr alarm, d->mAlarms ) { 00902 if ( alarm->enabled() ) { 00903 return true; 00904 } 00905 } 00906 return false; 00907 } 00908 00909 void Incidence::setLocation( const QString &location, bool isRich ) 00910 { 00911 if ( mReadOnly ) { 00912 return; 00913 } 00914 00915 update(); 00916 d->mLocation = location; 00917 d->mLocationIsRich = isRich; 00918 setFieldDirty( FieldLocation ); 00919 updated(); 00920 } 00921 00922 void Incidence::setLocation( const QString &location ) 00923 { 00924 setLocation( location, Qt::mightBeRichText( location ) ); 00925 } 00926 00927 QString Incidence::location() const 00928 { 00929 return d->mLocation; 00930 } 00931 00932 QString Incidence::richLocation() const 00933 { 00934 if ( locationIsRich() ) { 00935 return d->mLocation; 00936 } else { 00937 return Qt::escape( d->mLocation ).replace( '\n', "<br/>" ); 00938 } 00939 } 00940 00941 bool Incidence::locationIsRich() const 00942 { 00943 return d->mLocationIsRich; 00944 } 00945 00946 void Incidence::setSchedulingID( const QString &sid, const QString &uid ) 00947 { 00948 d->mSchedulingID = sid; 00949 if ( !uid.isEmpty() ) { 00950 setUid( uid ); 00951 } 00952 setFieldDirty( FieldSchedulingId ); 00953 } 00954 00955 QString Incidence::schedulingID() const 00956 { 00957 if ( d->mSchedulingID.isNull() ) { 00958 // Nothing set, so use the normal uid 00959 return uid(); 00960 } 00961 return d->mSchedulingID; 00962 } 00963 00964 bool Incidence::hasGeo() const 00965 { 00966 return d->mHasGeo; 00967 } 00968 00969 void Incidence::setHasGeo( bool hasGeo ) 00970 { 00971 if ( mReadOnly ) { 00972 return; 00973 } 00974 00975 if ( hasGeo == d->mHasGeo ) { 00976 return; 00977 } 00978 00979 update(); 00980 d->mHasGeo = hasGeo; 00981 setFieldDirty( FieldGeoLatitude ); 00982 setFieldDirty( FieldGeoLongitude ); 00983 updated(); 00984 } 00985 00986 float Incidence::geoLatitude() const 00987 { 00988 return d->mGeoLatitude; 00989 } 00990 00991 void Incidence::setGeoLatitude( float geolatitude ) 00992 { 00993 if ( mReadOnly ) { 00994 return; 00995 } 00996 00997 update(); 00998 d->mGeoLatitude = geolatitude; 00999 setFieldDirty( FieldGeoLatitude ); 01000 updated(); 01001 } 01002 01003 float Incidence::geoLongitude() const 01004 { 01005 return d->mGeoLongitude; 01006 } 01007 01008 void Incidence::setGeoLongitude( float geolongitude ) 01009 { 01010 if ( !mReadOnly ) { 01011 update(); 01012 d->mGeoLongitude = geolongitude; 01013 setFieldDirty( FieldGeoLongitude ); 01014 updated(); 01015 } 01016 } 01017 01018 bool Incidence::hasRecurrenceId() const 01019 { 01020 return d->mRecurrenceId.isValid(); 01021 } 01022 01023 KDateTime Incidence::recurrenceId() const 01024 { 01025 return d->mRecurrenceId; 01026 } 01027 01028 void Incidence::setRecurrenceId( const KDateTime &recurrenceId ) 01029 { 01030 if ( !mReadOnly ) { 01031 update(); 01032 d->mRecurrenceId = recurrenceId; 01033 setFieldDirty( FieldRecurrenceId ); 01034 updated(); 01035 } 01036 } 01037 01041 void Incidence::recurrenceUpdated( Recurrence *recurrence ) 01042 { 01043 if ( recurrence == d->mRecurrence ) { 01044 update(); 01045 updated(); 01046 } 01047 } 01048 01049 //@cond PRIVATE 01050 #define ALT_DESC_FIELD "X-ALT-DESC" 01051 #define ALT_DESC_PARAMETERS "FMTTYPE=text/html" 01052 //@endcond 01053 01054 bool Incidence::hasAltDescription() const 01055 { 01056 const QString value = nonKDECustomProperty( ALT_DESC_FIELD ); 01057 const QString parameter = nonKDECustomPropertyParameters( ALT_DESC_FIELD ); 01058 01059 return parameter == ALT_DESC_PARAMETERS && !value.isEmpty(); 01060 } 01061 01062 void Incidence::setAltDescription( const QString &altdescription ) 01063 { 01064 if ( altdescription.isEmpty() ) { 01065 removeNonKDECustomProperty( ALT_DESC_FIELD ); 01066 } else { 01067 setNonKDECustomProperty( ALT_DESC_FIELD, 01068 altdescription, 01069 ALT_DESC_PARAMETERS ); 01070 } 01071 } 01072 01073 QString Incidence::altDescription() const 01074 { 01075 if ( !hasAltDescription() ) { 01076 return QString(); 01077 } else { 01078 return nonKDECustomProperty( ALT_DESC_FIELD ); 01079 } 01080 }