KCalCore Library
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 KDateTime nowUTC = KDateTime::currentUtcDateTime(); 00294 setCreated( nowUTC ); 00295 00296 setSchedulingID( QString(), CalFormat::createUniqueId() ); 00297 00298 setRevision( 0 ); 00299 00300 setLastModified( nowUTC ); 00301 } 00302 00303 void Incidence::setLastModified( const KDateTime &lm ) 00304 { 00305 if ( !d->mLocalOnly ) { 00306 IncidenceBase::setLastModified( lm ); 00307 } 00308 } 00309 00310 void Incidence::setReadOnly( bool readOnly ) 00311 { 00312 IncidenceBase::setReadOnly( readOnly ); 00313 if ( d->mRecurrence ) { 00314 d->mRecurrence->setRecurReadOnly( readOnly ); 00315 } 00316 } 00317 00318 void Incidence::setLocalOnly( bool localOnly ) 00319 { 00320 if ( mReadOnly ) { 00321 return; 00322 } 00323 d->mLocalOnly = localOnly; 00324 } 00325 00326 bool Incidence::localOnly() const 00327 { 00328 return d->mLocalOnly; 00329 } 00330 00331 void Incidence::setAllDay( bool allDay ) 00332 { 00333 if ( mReadOnly ) { 00334 return; 00335 } 00336 if ( d->mRecurrence ) { 00337 d->mRecurrence->setAllDay( allDay ); 00338 } 00339 IncidenceBase::setAllDay( allDay ); 00340 } 00341 00342 void Incidence::setCreated( const KDateTime &created ) 00343 { 00344 if ( mReadOnly || d->mLocalOnly ) { 00345 return; 00346 } 00347 00348 d->mCreated = created.toUtc(); 00349 setFieldDirty( FieldCreated ); 00350 00351 // FIXME: Shouldn't we call updated for the creation date, too? 00352 // updated(); 00353 } 00354 00355 KDateTime Incidence::created() const 00356 { 00357 return d->mCreated; 00358 } 00359 00360 void Incidence::setRevision( int rev ) 00361 { 00362 if ( mReadOnly || d->mLocalOnly ) { 00363 return; 00364 } 00365 00366 update(); 00367 00368 d->mRevision = rev; 00369 setFieldDirty( FieldRevision ); 00370 updated(); 00371 } 00372 00373 int Incidence::revision() const 00374 { 00375 return d->mRevision; 00376 } 00377 00378 void Incidence::setDtStart( const KDateTime &dt ) 00379 { 00380 if ( d->mRecurrence ) { 00381 d->mRecurrence->setStartDateTime( dt ); 00382 d->mRecurrence->setAllDay( allDay() ); 00383 } 00384 IncidenceBase::setDtStart( dt ); 00385 } 00386 00387 void Incidence::shiftTimes( const KDateTime::Spec &oldSpec, 00388 const KDateTime::Spec &newSpec ) 00389 { 00390 IncidenceBase::shiftTimes( oldSpec, newSpec ); 00391 if ( d->mRecurrence ) { 00392 d->mRecurrence->shiftTimes( oldSpec, newSpec ); 00393 } 00394 for ( int i = 0, end = d->mAlarms.count(); i < end; ++i ) { 00395 d->mAlarms[i]->shiftTimes( oldSpec, newSpec ); 00396 } 00397 } 00398 00399 void Incidence::setDescription( const QString &description, bool isRich ) 00400 { 00401 if ( mReadOnly ) { 00402 return; 00403 } 00404 update(); 00405 d->mDescription = description; 00406 d->mDescriptionIsRich = isRich; 00407 setFieldDirty( FieldDescription ); 00408 updated(); 00409 } 00410 00411 void Incidence::setDescription( const QString &description ) 00412 { 00413 setDescription( description, Qt::mightBeRichText( description ) ); 00414 } 00415 00416 QString Incidence::description() const 00417 { 00418 return d->mDescription; 00419 } 00420 00421 QString Incidence::richDescription() const 00422 { 00423 if ( descriptionIsRich() ) { 00424 return d->mDescription; 00425 } else { 00426 return Qt::escape( d->mDescription ).replace( '\n', "<br/>" ); 00427 } 00428 } 00429 00430 bool Incidence::descriptionIsRich() const 00431 { 00432 return d->mDescriptionIsRich; 00433 } 00434 00435 void Incidence::setSummary( const QString &summary, bool isRich ) 00436 { 00437 if ( mReadOnly ) { 00438 return; 00439 } 00440 update(); 00441 d->mSummary = summary; 00442 d->mSummaryIsRich = isRich; 00443 setFieldDirty( FieldSummary ); 00444 updated(); 00445 } 00446 00447 void Incidence::setSummary( const QString &summary ) 00448 { 00449 setSummary( summary, Qt::mightBeRichText( summary ) ); 00450 } 00451 00452 QString Incidence::summary() const 00453 { 00454 return d->mSummary; 00455 } 00456 00457 QString Incidence::richSummary() const 00458 { 00459 if ( summaryIsRich() ) { 00460 return d->mSummary; 00461 } else { 00462 return Qt::escape( d->mSummary ).replace( '\n', "<br/>" ); 00463 } 00464 } 00465 00466 bool Incidence::summaryIsRich() const 00467 { 00468 return d->mSummaryIsRich; 00469 } 00470 00471 void Incidence::setCategories( const QStringList &categories ) 00472 { 00473 if ( mReadOnly ) { 00474 return; 00475 } 00476 00477 update(); 00478 d->mCategories = categories; 00479 updated(); 00480 } 00481 00482 void Incidence::setCategories( const QString &catStr ) 00483 { 00484 if ( mReadOnly ) { 00485 return; 00486 } 00487 update(); 00488 setFieldDirty( FieldCategories ); 00489 00490 d->mCategories.clear(); 00491 00492 if ( catStr.isEmpty() ) { 00493 updated(); 00494 return; 00495 } 00496 00497 d->mCategories = catStr.split( ',' ); 00498 00499 QStringList::Iterator it; 00500 for ( it = d->mCategories.begin();it != d->mCategories.end(); ++it ) { 00501 *it = (*it).trimmed(); 00502 } 00503 00504 updated(); 00505 } 00506 00507 QStringList Incidence::categories() const 00508 { 00509 return d->mCategories; 00510 } 00511 00512 QString Incidence::categoriesStr() const 00513 { 00514 return d->mCategories.join( "," ); 00515 } 00516 00517 void Incidence::setRelatedTo( const QString &relatedToUid, RelType relType ) 00518 { 00519 // TODO: RFC says that an incidence can have more than one related-to field 00520 // even for the same relType. 00521 00522 if ( d->mRelatedToUid[relType] != relatedToUid ) { 00523 update(); 00524 d->mRelatedToUid[relType] = relatedToUid; 00525 setFieldDirty( FieldRelatedTo ); 00526 updated(); 00527 } 00528 } 00529 00530 QString Incidence::relatedTo( RelType relType ) const 00531 { 00532 return d->mRelatedToUid.value( relType ); 00533 } 00534 00535 // %%%%%%%%%%%% Recurrence-related methods %%%%%%%%%%%%%%%%%%%% 00536 00537 Recurrence *Incidence::recurrence() const 00538 { 00539 if ( !d->mRecurrence ) { 00540 d->mRecurrence = new Recurrence(); 00541 d->mRecurrence->setStartDateTime( IncidenceBase::dtStart() ); 00542 d->mRecurrence->setAllDay( allDay() ); 00543 d->mRecurrence->setRecurReadOnly( mReadOnly ); 00544 d->mRecurrence->addObserver( const_cast<KCalCore::Incidence*>( this ) ); 00545 } 00546 00547 return d->mRecurrence; 00548 } 00549 00550 void Incidence::clearRecurrence() 00551 { 00552 delete d->mRecurrence; 00553 d->mRecurrence = 0; 00554 } 00555 00556 ushort Incidence::recurrenceType() const 00557 { 00558 if ( d->mRecurrence ) { 00559 return d->mRecurrence->recurrenceType(); 00560 } else { 00561 return Recurrence::rNone; 00562 } 00563 } 00564 00565 bool Incidence::recurs() const 00566 { 00567 if ( d->mRecurrence ) { 00568 return d->mRecurrence->recurs(); 00569 } else { 00570 return false; 00571 } 00572 } 00573 00574 bool Incidence::recursOn( const QDate &date, 00575 const KDateTime::Spec &timeSpec ) const 00576 { 00577 return d->mRecurrence && d->mRecurrence->recursOn( date, timeSpec ); 00578 } 00579 00580 bool Incidence::recursAt( const KDateTime &qdt ) const 00581 { 00582 return d->mRecurrence && d->mRecurrence->recursAt( qdt ); 00583 } 00584 00585 QList<KDateTime> Incidence::startDateTimesForDate( const QDate &date, 00586 const KDateTime::Spec &timeSpec ) const 00587 { 00588 KDateTime start = dtStart(); 00589 KDateTime end = dateTime( RoleEndRecurrenceBase ); 00590 00591 QList<KDateTime> result; 00592 00593 // TODO_Recurrence: Also work if only due date is given... 00594 if ( !start.isValid() && ! end.isValid() ) { 00595 return result; 00596 } 00597 00598 // if the incidence doesn't recur, 00599 KDateTime kdate( date, timeSpec ); 00600 if ( !recurs() ) { 00601 if ( !( start > kdate || end < kdate ) ) { 00602 result << start; 00603 } 00604 return result; 00605 } 00606 00607 int days = start.daysTo( end ); 00608 // Account for possible recurrences going over midnight, while the original event doesn't 00609 QDate tmpday( date.addDays( -days - 1 ) ); 00610 KDateTime tmp; 00611 while ( tmpday <= date ) { 00612 if ( recurrence()->recursOn( tmpday, timeSpec ) ) { 00613 QList<QTime> times = recurrence()->recurTimesOn( tmpday, timeSpec ); 00614 foreach ( const QTime &time, times ) { 00615 tmp = KDateTime( tmpday, time, start.timeSpec() ); 00616 if ( endDateForStart( tmp ) >= kdate ) { 00617 result << tmp; 00618 } 00619 } 00620 } 00621 tmpday = tmpday.addDays( 1 ); 00622 } 00623 return result; 00624 } 00625 00626 QList<KDateTime> Incidence::startDateTimesForDateTime( const KDateTime &datetime ) const 00627 { 00628 KDateTime start = dtStart(); 00629 KDateTime end = dateTime( RoleEndRecurrenceBase ); 00630 00631 QList<KDateTime> result; 00632 00633 // TODO_Recurrence: Also work if only due date is given... 00634 if ( !start.isValid() && ! end.isValid() ) { 00635 return result; 00636 } 00637 00638 // if the incidence doesn't recur, 00639 if ( !recurs() ) { 00640 if ( !( start > datetime || end < datetime ) ) { 00641 result << start; 00642 } 00643 return result; 00644 } 00645 00646 int days = start.daysTo( end ); 00647 // Account for possible recurrences going over midnight, while the original event doesn't 00648 QDate tmpday( datetime.date().addDays( -days - 1 ) ); 00649 KDateTime tmp; 00650 while ( tmpday <= datetime.date() ) { 00651 if ( recurrence()->recursOn( tmpday, datetime.timeSpec() ) ) { 00652 // Get the times during the day (in start date's time zone) when recurrences happen 00653 QList<QTime> times = recurrence()->recurTimesOn( tmpday, start.timeSpec() ); 00654 foreach ( const QTime &time, times ) { 00655 tmp = KDateTime( tmpday, time, start.timeSpec() ); 00656 if ( !( tmp > datetime || endDateForStart( tmp ) < datetime ) ) { 00657 result << tmp; 00658 } 00659 } 00660 } 00661 tmpday = tmpday.addDays( 1 ); 00662 } 00663 return result; 00664 } 00665 00666 KDateTime Incidence::endDateForStart( const KDateTime &startDt ) const 00667 { 00668 KDateTime start = dtStart(); 00669 KDateTime end = dateTime( RoleEndRecurrenceBase ); 00670 if ( !end.isValid() ) { 00671 return start; 00672 } 00673 if ( !start.isValid() ) { 00674 return end; 00675 } 00676 00677 return startDt.addSecs( start.secsTo( end ) ); 00678 } 00679 00680 void Incidence::addAttachment( const Attachment::Ptr &attachment ) 00681 { 00682 if ( mReadOnly || !attachment ) { 00683 return; 00684 } 00685 00686 Q_ASSERT( !d->mAttachments.contains( attachment ) ); 00687 00688 update(); 00689 d->mAttachments.append( attachment ); 00690 setFieldDirty( FieldAttachment ); 00691 updated(); 00692 } 00693 00694 void Incidence::deleteAttachment( const Attachment::Ptr &attachment ) 00695 { 00696 int index = d->mAttachments.indexOf( attachment ); 00697 if ( index > -1 ) { 00698 setFieldDirty( FieldAttachment ); 00699 d->mAttachments.remove( index ); 00700 } 00701 } 00702 00703 void Incidence::deleteAttachments( const QString &mime ) 00704 { 00705 Attachment::List result; 00706 Attachment::List::Iterator it = d->mAttachments.begin(); 00707 while ( it != d->mAttachments.end() ) { 00708 if ( (*it)->mimeType() != mime ) { 00709 result += *it; 00710 } 00711 ++it; 00712 } 00713 d->mAttachments = result; 00714 setFieldDirty( FieldAttachment ); 00715 } 00716 00717 Attachment::List Incidence::attachments() const 00718 { 00719 return d->mAttachments; 00720 } 00721 00722 Attachment::List Incidence::attachments( const QString &mime ) const 00723 { 00724 Attachment::List attachments; 00725 foreach ( Attachment::Ptr attachment, d->mAttachments ) { 00726 if ( attachment->mimeType() == mime ) { 00727 attachments.append( attachment ); 00728 } 00729 } 00730 return attachments; 00731 } 00732 00733 void Incidence::clearAttachments() 00734 { 00735 setFieldDirty( FieldAttachment ); 00736 d->mAttachments.clear(); 00737 } 00738 00739 QString Incidence::writeAttachmentToTempFile( const Attachment::Ptr &attachment ) const 00740 { 00741 if ( d->mTempFiles.contains( attachment ) ) { 00742 return d->mTempFiles.value( attachment ); 00743 } 00744 KTemporaryFile *file = new KTemporaryFile(); 00745 00746 QStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns(); 00747 00748 if ( !patterns.empty() ) { 00749 file->setSuffix( QString( patterns.first() ).remove( '*' ) ); 00750 } 00751 file->setAutoRemove( true ); 00752 file->open(); 00753 // read-only not to give the idea that it could be written to 00754 file->setPermissions( QFile::ReadUser ); 00755 file->write( QByteArray::fromBase64( attachment->data() ) ); 00756 d->mTempFiles.insert( attachment, file->fileName() ); 00757 file->close(); 00758 return d->mTempFiles.value( attachment ); 00759 } 00760 00761 void Incidence::clearTempFiles() 00762 { 00763 QHash<Attachment::Ptr,QString>::const_iterator it = d->mTempFiles.constBegin(); 00764 const QHash<Attachment::Ptr,QString>::const_iterator end = d->mTempFiles.constEnd(); 00765 for ( ; it != end; ++it ) { 00766 QFile::remove( it.value() ); 00767 } 00768 d->mTempFiles.clear(); 00769 } 00770 00771 void Incidence::setResources( const QStringList &resources ) 00772 { 00773 if ( mReadOnly ) { 00774 return; 00775 } 00776 00777 update(); 00778 d->mResources = resources; 00779 setFieldDirty( FieldResources ); 00780 updated(); 00781 } 00782 00783 QStringList Incidence::resources() const 00784 { 00785 return d->mResources; 00786 } 00787 00788 void Incidence::setPriority( int priority ) 00789 { 00790 if ( mReadOnly ) { 00791 return; 00792 } 00793 00794 update(); 00795 d->mPriority = priority; 00796 setFieldDirty( FieldPriority ); 00797 updated(); 00798 } 00799 00800 int Incidence::priority() const 00801 { 00802 return d->mPriority; 00803 } 00804 00805 void Incidence::setStatus( Incidence::Status status ) 00806 { 00807 if ( mReadOnly || status == StatusX ) { 00808 return; 00809 } 00810 00811 update(); 00812 d->mStatus = status; 00813 d->mStatusString.clear(); 00814 setFieldDirty( FieldStatus ); 00815 updated(); 00816 } 00817 00818 void Incidence::setCustomStatus( const QString &status ) 00819 { 00820 if ( mReadOnly ) { 00821 return; 00822 } 00823 00824 update(); 00825 d->mStatus = status.isEmpty() ? StatusNone : StatusX; 00826 d->mStatusString = status; 00827 setFieldDirty( FieldStatus ); 00828 updated(); 00829 } 00830 00831 Incidence::Status Incidence::status() const 00832 { 00833 return d->mStatus; 00834 } 00835 00836 QString Incidence::customStatus() const 00837 { 00838 if ( d->mStatus == StatusX ) { 00839 return d->mStatusString; 00840 } else { 00841 return QString(); 00842 } 00843 } 00844 00845 void Incidence::setSecrecy( Incidence::Secrecy secrecy ) 00846 { 00847 if ( mReadOnly ) { 00848 return; 00849 } 00850 00851 update(); 00852 d->mSecrecy = secrecy; 00853 setFieldDirty( FieldSecrecy ); 00854 updated(); 00855 } 00856 00857 Incidence::Secrecy Incidence::secrecy() const 00858 { 00859 return d->mSecrecy; 00860 } 00861 00862 Alarm::List Incidence::alarms() const 00863 { 00864 return d->mAlarms; 00865 } 00866 00867 Alarm::Ptr Incidence::newAlarm() 00868 { 00869 Alarm::Ptr alarm( new Alarm( this ) ); 00870 d->mAlarms.append( alarm ); 00871 return alarm; 00872 } 00873 00874 void Incidence::addAlarm( const Alarm::Ptr &alarm ) 00875 { 00876 update(); 00877 d->mAlarms.append( alarm ); 00878 setFieldDirty( FieldAlarms ); 00879 updated(); 00880 } 00881 00882 void Incidence::removeAlarm( const Alarm::Ptr &alarm ) 00883 { 00884 const int index = d->mAlarms.indexOf( alarm ); 00885 if ( index > -1 ) { 00886 update(); 00887 d->mAlarms.remove( index ); 00888 setFieldDirty( FieldAlarms ); 00889 updated(); 00890 } 00891 } 00892 00893 void Incidence::clearAlarms() 00894 { 00895 update(); 00896 d->mAlarms.clear(); 00897 setFieldDirty( FieldAlarms ); 00898 updated(); 00899 } 00900 00901 bool Incidence::hasEnabledAlarms() const 00902 { 00903 foreach ( Alarm::Ptr alarm, d->mAlarms ) { 00904 if ( alarm->enabled() ) { 00905 return true; 00906 } 00907 } 00908 return false; 00909 } 00910 00911 void Incidence::setLocation( const QString &location, bool isRich ) 00912 { 00913 if ( mReadOnly ) { 00914 return; 00915 } 00916 00917 update(); 00918 d->mLocation = location; 00919 d->mLocationIsRich = isRich; 00920 setFieldDirty( FieldLocation ); 00921 updated(); 00922 } 00923 00924 void Incidence::setLocation( const QString &location ) 00925 { 00926 setLocation( location, Qt::mightBeRichText( location ) ); 00927 } 00928 00929 QString Incidence::location() const 00930 { 00931 return d->mLocation; 00932 } 00933 00934 QString Incidence::richLocation() const 00935 { 00936 if ( locationIsRich() ) { 00937 return d->mLocation; 00938 } else { 00939 return Qt::escape( d->mLocation ).replace( '\n', "<br/>" ); 00940 } 00941 } 00942 00943 bool Incidence::locationIsRich() const 00944 { 00945 return d->mLocationIsRich; 00946 } 00947 00948 void Incidence::setSchedulingID( const QString &sid, const QString &uid ) 00949 { 00950 d->mSchedulingID = sid; 00951 if ( !uid.isEmpty() ) { 00952 setUid( uid ); 00953 } 00954 setFieldDirty( FieldSchedulingId ); 00955 } 00956 00957 QString Incidence::schedulingID() const 00958 { 00959 if ( d->mSchedulingID.isNull() ) { 00960 // Nothing set, so use the normal uid 00961 return uid(); 00962 } 00963 return d->mSchedulingID; 00964 } 00965 00966 bool Incidence::hasGeo() const 00967 { 00968 return d->mHasGeo; 00969 } 00970 00971 void Incidence::setHasGeo( bool hasGeo ) 00972 { 00973 if ( mReadOnly ) { 00974 return; 00975 } 00976 00977 if ( hasGeo == d->mHasGeo ) { 00978 return; 00979 } 00980 00981 update(); 00982 d->mHasGeo = hasGeo; 00983 setFieldDirty( FieldGeoLatitude ); 00984 setFieldDirty( FieldGeoLongitude ); 00985 updated(); 00986 } 00987 00988 float Incidence::geoLatitude() const 00989 { 00990 return d->mGeoLatitude; 00991 } 00992 00993 void Incidence::setGeoLatitude( float geolatitude ) 00994 { 00995 if ( mReadOnly ) { 00996 return; 00997 } 00998 00999 update(); 01000 d->mGeoLatitude = geolatitude; 01001 setFieldDirty( FieldGeoLatitude ); 01002 updated(); 01003 } 01004 01005 float Incidence::geoLongitude() const 01006 { 01007 return d->mGeoLongitude; 01008 } 01009 01010 void Incidence::setGeoLongitude( float geolongitude ) 01011 { 01012 if ( !mReadOnly ) { 01013 update(); 01014 d->mGeoLongitude = geolongitude; 01015 setFieldDirty( FieldGeoLongitude ); 01016 updated(); 01017 } 01018 } 01019 01020 bool Incidence::hasRecurrenceId() const 01021 { 01022 return d->mRecurrenceId.isValid(); 01023 } 01024 01025 KDateTime Incidence::recurrenceId() const 01026 { 01027 return d->mRecurrenceId; 01028 } 01029 01030 void Incidence::setRecurrenceId( const KDateTime &recurrenceId ) 01031 { 01032 if ( !mReadOnly ) { 01033 update(); 01034 d->mRecurrenceId = recurrenceId; 01035 setFieldDirty( FieldRecurrenceId ); 01036 updated(); 01037 } 01038 } 01039 01043 void Incidence::recurrenceUpdated( Recurrence *recurrence ) 01044 { 01045 if ( recurrence == d->mRecurrence ) { 01046 update(); 01047 updated(); 01048 } 01049 } 01050 01051 //@cond PRIVATE 01052 #define ALT_DESC_FIELD "X-ALT-DESC" 01053 #define ALT_DESC_PARAMETERS "FMTTYPE=text/html" 01054 //@endcond 01055 01056 bool Incidence::hasAltDescription() const 01057 { 01058 const QString value = nonKDECustomProperty( ALT_DESC_FIELD ); 01059 const QString parameter = nonKDECustomPropertyParameters( ALT_DESC_FIELD ); 01060 01061 return parameter == ALT_DESC_PARAMETERS && !value.isEmpty(); 01062 } 01063 01064 void Incidence::setAltDescription( const QString &altdescription ) 01065 { 01066 if ( altdescription.isEmpty() ) { 01067 removeNonKDECustomProperty( ALT_DESC_FIELD ); 01068 } else { 01069 setNonKDECustomProperty( ALT_DESC_FIELD, 01070 altdescription, 01071 ALT_DESC_PARAMETERS ); 01072 } 01073 } 01074 01075 QString Incidence::altDescription() const 01076 { 01077 if ( !hasAltDescription() ) { 01078 return QString(); 01079 } else { 01080 return nonKDECustomProperty( ALT_DESC_FIELD ); 01081 } 01082 }