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