libkcal

resourcecached.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include <qdatastream.h>
00023 #include <qdatetime.h>
00024 #include <qfile.h>
00025 #include <qstring.h>
00026 #include <qptrlist.h>
00027 
00028 #include <kdebug.h>
00029 #include <klocale.h>
00030 #include <kurl.h>
00031 #include <kstandarddirs.h>
00032 
00033 #include "event.h"
00034 #include "exceptions.h"
00035 #include "incidence.h"
00036 #include "journal.h"
00037 #include "todo.h"
00038 #include <unistd.h>
00039 
00040 
00041 #include "resourcecached.h"
00042 
00043 using namespace KCal;
00044 
00045 ResourceCached::ResourceCached( const KConfig* config )
00046   : ResourceCalendar( config ), mCalendar( QString::fromLatin1( "UTC" ) ),
00047     mReloadPolicy( ReloadNever ),  mReloadInterval( 10 ),
00048     mReloadTimer( 0, "mReloadTimer" ), mReloaded( false ),
00049     mSavePolicy( SaveNever ), mSaveInterval( 10 ),
00050     mSaveTimer( 0, "mSaveTimer" ), mIdMapper( "kcal/uidmaps/" )
00051 {
00052   connect( &mReloadTimer, SIGNAL( timeout() ), SLOT( slotReload() ) );
00053   connect( &mSaveTimer, SIGNAL( timeout() ), SLOT( slotSave() ) );
00054 }
00055 
00056 ResourceCached::~ResourceCached()
00057 {
00058 }
00059 
00060 void ResourceCached::setReloadPolicy( int i )
00061 {
00062   mReloadPolicy = i;
00063 
00064   setupReloadTimer();
00065 }
00066 
00067 int ResourceCached::reloadPolicy() const
00068 {
00069   return mReloadPolicy;
00070 }
00071 
00072 void ResourceCached::setReloadInterval( int minutes )
00073 {
00074   mReloadInterval = minutes;
00075 }
00076 
00077 int ResourceCached::reloadInterval() const
00078 {
00079   return mReloadInterval;
00080 }
00081 
00082 void ResourceCached::setSavePolicy( int i )
00083 {
00084   mSavePolicy = i;
00085 
00086   setupSaveTimer();
00087 }
00088 
00089 int ResourceCached::savePolicy() const
00090 {
00091   return mSavePolicy;
00092 }
00093 
00094 void ResourceCached::setSaveInterval( int minutes )
00095 {
00096   mSaveInterval = minutes;
00097 }
00098 
00099 int ResourceCached::saveInterval() const
00100 {
00101   return mSaveInterval;
00102 }
00103 
00104 void ResourceCached::readConfig( const KConfig *config )
00105 {
00106   mReloadPolicy = config->readNumEntry( "ReloadPolicy", ReloadNever );
00107   mReloadInterval = config->readNumEntry( "ReloadInterval", 10 );
00108 
00109   mSaveInterval = config->readNumEntry( "SaveInterval", 10 );
00110   mSavePolicy = config->readNumEntry( "SavePolicy", SaveNever );
00111 
00112   mLastLoad = config->readDateTimeEntry( "LastLoad" );
00113   mLastSave = config->readDateTimeEntry( "LastSave" );
00114 
00115   setupSaveTimer();
00116   setupReloadTimer();
00117 }
00118 
00119 void ResourceCached::setupSaveTimer()
00120 {
00121   if ( mSavePolicy == SaveInterval ) {
00122     kdDebug(5800) << "ResourceCached::setSavePolicy(): start save timer (interval "
00123               << mSaveInterval << " minutes)." << endl;
00124     mSaveTimer.start( mSaveInterval * 60 * 1000 ); // n minutes
00125   } else {
00126     mSaveTimer.stop();
00127   }
00128 }
00129 
00130 void ResourceCached::setupReloadTimer()
00131 {
00132   if ( mReloadPolicy == ReloadInterval ) {
00133     kdDebug(5800) << "ResourceCached::setSavePolicy(): start reload timer "
00134                  "(interval " << mReloadInterval << " minutes)" << endl;
00135     mReloadTimer.start( mReloadInterval * 60 * 1000 ); // n minutes
00136   } else {
00137     mReloadTimer.stop();
00138   }
00139 }
00140 
00141 void ResourceCached::writeConfig( KConfig *config )
00142 {
00143   config->writeEntry( "ReloadPolicy", mReloadPolicy );
00144   config->writeEntry( "ReloadInterval", mReloadInterval );
00145 
00146   config->writeEntry( "SavePolicy", mSavePolicy );
00147   config->writeEntry( "SaveInterval", mSaveInterval );
00148 
00149   config->writeEntry( "LastLoad", mLastLoad );
00150   config->writeEntry( "LastSave", mLastSave );
00151 }
00152 
00153 bool ResourceCached::addEvent(Event *event)
00154 {
00155   return mCalendar.addEvent( event );
00156 }
00157 
00158 bool ResourceCached::addEvent(Event *event, const QString &subresource )
00159 {
00160   Q_UNUSED( subresource ); // CalendarLocal does not support subresources
00161   return mCalendar.addEvent( event );
00162 }
00163 
00164 // probably not really efficient, but...it works for now.
00165 bool ResourceCached::deleteEvent( Event *event )
00166 {
00167   kdDebug(5800) << "ResourceCached::deleteEvent" << endl;
00168 
00169   return mCalendar.deleteEvent( event );
00170 }
00171 
00172 
00173 Event *ResourceCached::event( const QString &uid )
00174 {
00175   return mCalendar.event( uid );
00176 }
00177 
00178 Event::List ResourceCached::rawEventsForDate( const QDate &qd,
00179                                               EventSortField sortField,
00180                                               SortDirection sortDirection )
00181 {
00182   Event::List list = mCalendar.rawEventsForDate( qd, sortField, sortDirection );
00183 
00184   return list;
00185 }
00186 
00187 Event::List ResourceCached::rawEvents( const QDate &start, const QDate &end,
00188                                        bool inclusive )
00189 {
00190   return mCalendar.rawEvents( start, end, inclusive );
00191 }
00192 
00193 Event::List ResourceCached::rawEventsForDate( const QDateTime &qdt )
00194 {
00195   return mCalendar.rawEventsForDate( qdt.date() );
00196 }
00197 
00198 Event::List ResourceCached::rawEvents( EventSortField sortField, SortDirection sortDirection )
00199 {
00200   return mCalendar.rawEvents( sortField, sortDirection );
00201 }
00202 
00203 bool ResourceCached::addTodo( Todo *todo )
00204 {
00205   return mCalendar.addTodo( todo );
00206 }
00207 
00208 bool ResourceCached::addTodo( Todo *todo, const QString &subresource )
00209 {
00210   Q_UNUSED( subresource ); // CalendarLocal does not support subresources
00211   return mCalendar.addTodo( todo );
00212 }
00213 
00214 bool ResourceCached::deleteTodo( Todo *todo )
00215 {
00216   return mCalendar.deleteTodo( todo );
00217 }
00218 
00219 bool ResourceCached::deleteJournal( Journal *journal )
00220 {
00221   return mCalendar.deleteJournal( journal );
00222 }
00223 
00224 
00225 Todo::List ResourceCached::rawTodos( TodoSortField sortField, SortDirection sortDirection )
00226 {
00227   return mCalendar.rawTodos( sortField, sortDirection );
00228 }
00229 
00230 Todo *ResourceCached::todo( const QString &uid )
00231 {
00232   return mCalendar.todo( uid );
00233 }
00234 
00235 Todo::List ResourceCached::rawTodosForDate( const QDate &date )
00236 {
00237   return mCalendar.rawTodosForDate( date );
00238 }
00239 
00240 bool ResourceCached::addJournal( Journal *journal )
00241 {
00242   return mCalendar.addJournal( journal );
00243 }
00244 
00245 bool ResourceCached::addJournal( Journal *journal, const QString &subresource )
00246 {
00247   Q_UNUSED( subresource ); // CalendarLocal does not support subresources
00248   return mCalendar.addJournal( journal );
00249 }
00250 
00251 Journal *ResourceCached::journal( const QString &uid )
00252 {
00253   return mCalendar.journal( uid );
00254 }
00255 
00256 Journal::List ResourceCached::rawJournals( JournalSortField sortField, SortDirection sortDirection )
00257 {
00258   return mCalendar.rawJournals( sortField, sortDirection );
00259 }
00260 
00261 Journal::List ResourceCached::rawJournalsForDate( const QDate &date )
00262 {
00263   return mCalendar.rawJournalsForDate( date );
00264 }
00265 
00266 
00267 Alarm::List ResourceCached::alarmsTo( const QDateTime &to )
00268 {
00269   return mCalendar.alarmsTo( to );
00270 }
00271 
00272 Alarm::List ResourceCached::alarms( const QDateTime &from, const QDateTime &to )
00273 {
00274   // kdDebug(5800) << "ResourceCached::alarms(" << from.toString() << " - " << to.toString() << ")\n";
00275   return mCalendar.alarms( from, to );
00276 }
00277 
00278 
00279 void ResourceCached::setTimeZoneId( const QString& tzid )
00280 {
00281   mCalendar.setTimeZoneId( tzid );
00282 }
00283 
00284 QString ResourceCached::timeZoneId() const
00285 {
00286   return mCalendar.timeZoneId();
00287 }
00288 
00289 void ResourceCached::clearChanges()
00290 {
00291   mAddedIncidences.clear();
00292   mChangedIncidences.clear();
00293   mDeletedIncidences.clear();
00294 }
00295 
00296 void ResourceCached::loadCache()
00297 {
00298   setIdMapperIdentifier();
00299   mIdMapper.load();
00300 
00301   if ( KStandardDirs::exists( cacheFile() ) ) {
00302     mCalendar.load( cacheFile() );
00303     if ( readOnly() ) {
00304       Incidence::List incidences( rawIncidences() );
00305       Incidence::List::Iterator it;
00306       for ( it = incidences.begin(); it != incidences.end(); ++it ) {
00307         (*it)->setReadOnly( true );
00308       }
00309     }
00310   }
00311 }
00312 
00313 void ResourceCached::saveCache()
00314 {
00315   kdDebug(5800) << "ResourceCached::saveCache(): " << cacheFile() << endl;
00316 
00317   setIdMapperIdentifier();
00318   mIdMapper.save();
00319 
00320   mCalendar.save( cacheFile() );
00321 }
00322 
00323 void ResourceCached::setIdMapperIdentifier()
00324 {
00325   mIdMapper.setIdentifier( type() + "_" + identifier() );
00326 }
00327 
00328 void ResourceCached::clearCache()
00329 {
00330   mCalendar.close();
00331 }
00332 
00333 void ResourceCached::cleanUpEventCache( const Event::List &eventList )
00334 {
00335   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00336 
00337   if ( KStandardDirs::exists( cacheFile() ) )
00338     calendar.load( cacheFile() );
00339   else
00340     return;
00341 
00342   Event::List list = calendar.events();
00343   Event::List::ConstIterator cacheIt, it;
00344   for ( cacheIt = list.begin(); cacheIt != list.end(); ++cacheIt ) {
00345     bool found = false;
00346     for ( it = eventList.begin(); it != eventList.end(); ++it ) {
00347       if ( (*it)->uid() == (*cacheIt)->uid() )
00348         found = true;
00349     }
00350 
00351     if ( !found ) {
00352       mIdMapper.removeRemoteId( mIdMapper.remoteId( (*cacheIt)->uid() ) );
00353       Event *event = mCalendar.event( (*cacheIt)->uid() );
00354       if ( event )
00355         mCalendar.deleteEvent( event );
00356     }
00357   }
00358 
00359   calendar.close();
00360 }
00361 
00362 void ResourceCached::cleanUpTodoCache( const Todo::List &todoList )
00363 {
00364   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00365 
00366   if ( KStandardDirs::exists( cacheFile() ) )
00367     calendar.load( cacheFile() );
00368   else
00369     return;
00370 
00371   Todo::List list = calendar.todos();
00372   Todo::List::ConstIterator cacheIt, it;
00373   for ( cacheIt = list.begin(); cacheIt != list.end(); ++cacheIt ) {
00374 
00375     bool found = false;
00376     for ( it = todoList.begin(); it != todoList.end(); ++it ) {
00377       if ( (*it)->uid() == (*cacheIt)->uid() )
00378         found = true;
00379     }
00380 
00381     if ( !found ) {
00382       mIdMapper.removeRemoteId( mIdMapper.remoteId( (*cacheIt)->uid() ) );
00383       Todo *todo = mCalendar.todo( (*cacheIt)->uid() );
00384       if ( todo )
00385         mCalendar.deleteTodo( todo );
00386     }
00387   }
00388 
00389   calendar.close();
00390 }
00391 
00392 KPIM::IdMapper& ResourceCached::idMapper()
00393 {
00394   return mIdMapper;
00395 }
00396 
00397 QString ResourceCached::cacheFile() const
00398 {
00399   return locateLocal( "cache", "kcal/kresources/" + identifier() );
00400 }
00401 
00402 QString ResourceCached::changesCacheFile( const QString &type ) const
00403 {
00404   return locateLocal( "cache", "kcal/changescache/" + identifier() + "_" + type );
00405 }
00406 
00407 void ResourceCached::saveChangesCache( const QMap<Incidence*, bool> &map, const QString &type )
00408 {
00409   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00410 
00411   bool isEmpty = true;
00412   QMap<Incidence *,bool>::ConstIterator it;
00413   for ( it = map.begin(); it != map.end(); ++it ) {
00414     isEmpty = false;
00415     calendar.addIncidence( it.key()->clone() );
00416   }
00417 
00418   if ( !isEmpty ) {
00419     calendar.save( changesCacheFile( type ) );
00420   } else {
00421     QFile file( changesCacheFile( type ) );
00422     file.remove();
00423   }
00424 
00425   calendar.close();
00426 }
00427 
00428 void ResourceCached::saveChangesCache()
00429 {
00430   saveChangesCache( mAddedIncidences, "added" );
00431   saveChangesCache( mDeletedIncidences, "deleted" );
00432   saveChangesCache( mChangedIncidences, "changed" );
00433 }
00434 
00435 void ResourceCached::loadChangesCache( QMap<Incidence*, bool> &map, const QString &type )
00436 {
00437   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00438 
00439   if ( KStandardDirs::exists( changesCacheFile( type ) ) )
00440     calendar.load( changesCacheFile( type ) );
00441   else
00442     return;
00443 
00444   const Incidence::List list = calendar.incidences();
00445   Incidence::List::ConstIterator it;
00446   for ( it = list.begin(); it != list.end(); ++it )
00447     map.insert( (*it)->clone(), true );
00448 
00449   calendar.close();
00450 }
00451 
00452 void ResourceCached::loadChangesCache()
00453 {
00454   loadChangesCache( mAddedIncidences, "added" );
00455   loadChangesCache( mDeletedIncidences, "deleted" );
00456   loadChangesCache( mChangedIncidences, "changed" );
00457 }
00458 
00459 void ResourceCached::calendarIncidenceAdded( Incidence *i )
00460 {
00461 #if 1
00462   kdDebug(5800) << "ResourceCached::calendarIncidenceAdded(): "
00463             << i->uid() << endl;
00464 #endif
00465 
00466   QMap<Incidence *,bool>::ConstIterator it;
00467   it = mAddedIncidences.find( i );
00468   if ( it == mAddedIncidences.end() ) {
00469     mAddedIncidences.insert( i, true );
00470   }
00471 
00472   checkForAutomaticSave();
00473 }
00474 
00475 void ResourceCached::calendarIncidenceChanged( Incidence *i )
00476 {
00477 #if 1
00478   kdDebug(5800) << "ResourceCached::calendarIncidenceChanged(): "
00479             << i->uid() << endl;
00480 #endif
00481 
00482   QMap<Incidence *,bool>::ConstIterator it;
00483   it = mChangedIncidences.find( i );
00484   // FIXME: If you modify an added incidence, there's no need to add it to mChangedIncidences!
00485   if ( it == mChangedIncidences.end() ) {
00486     mChangedIncidences.insert( i, true );
00487   }
00488 
00489   checkForAutomaticSave();
00490 }
00491 
00492 void ResourceCached::calendarIncidenceDeleted( Incidence *i )
00493 {
00494 #if 1
00495   kdDebug(5800) << "ResourceCached::calendarIncidenceDeleted(): "
00496             << i->uid() << endl;
00497 #endif
00498 
00499   QMap<Incidence *,bool>::ConstIterator it;
00500   it = mDeletedIncidences.find( i );
00501   if ( it == mDeletedIncidences.end() ) {
00502     mDeletedIncidences.insert( i, true );
00503   }
00504 
00505   checkForAutomaticSave();
00506 }
00507 
00508 Incidence::List ResourceCached::addedIncidences() const
00509 {
00510   Incidence::List added;
00511   QMap<Incidence *,bool>::ConstIterator it;
00512   for( it = mAddedIncidences.begin(); it != mAddedIncidences.end(); ++it ) {
00513     added.append( it.key() );
00514   }
00515   return added;
00516 }
00517 
00518 Incidence::List ResourceCached::changedIncidences() const
00519 {
00520   Incidence::List changed;
00521   QMap<Incidence *,bool>::ConstIterator it;
00522   for( it = mChangedIncidences.begin(); it != mChangedIncidences.end(); ++it ) {
00523     changed.append( it.key() );
00524   }
00525   return changed;
00526 }
00527 
00528 Incidence::List ResourceCached::deletedIncidences() const
00529 {
00530   Incidence::List deleted;
00531   QMap<Incidence *,bool>::ConstIterator it;
00532   for( it = mDeletedIncidences.begin(); it != mDeletedIncidences.end(); ++it ) {
00533     deleted.append( it.key() );
00534   }
00535   return deleted;
00536 }
00537 
00538 Incidence::List ResourceCached::allChanges() const
00539 {
00540   Incidence::List changes;
00541   QMap<Incidence *,bool>::ConstIterator it;
00542   for( it = mAddedIncidences.begin(); it != mAddedIncidences.end(); ++it ) {
00543     changes.append( it.key() );
00544   }
00545   for( it = mChangedIncidences.begin(); it != mChangedIncidences.end(); ++it ) {
00546     changes.append( it.key() );
00547   }
00548   for( it = mDeletedIncidences.begin(); it != mDeletedIncidences.end(); ++it ) {
00549     changes.append( it.key() );
00550   }
00551   return changes;
00552 }
00553 
00554 bool ResourceCached::hasChanges() const
00555 {
00556   return !( mAddedIncidences.isEmpty() && mChangedIncidences.isEmpty() &&
00557             mDeletedIncidences.isEmpty() );
00558 }
00559 
00560 void ResourceCached::clearChange( Incidence *incidence )
00561 {
00562   clearChange( incidence->uid() );
00563 }
00564 
00565 void ResourceCached::clearChange( const QString &uid )
00566 {
00567   QMap<Incidence*, bool>::Iterator it;
00568 
00569   for ( it = mAddedIncidences.begin(); it != mAddedIncidences.end(); ++it )
00570     if ( it.key()->uid() == uid ) {
00571       mAddedIncidences.remove( it );
00572       break;
00573     }
00574 
00575   for ( it = mChangedIncidences.begin(); it != mChangedIncidences.end(); ++it )
00576     if ( it.key()->uid() == uid ) {
00577       mChangedIncidences.remove( it );
00578       break;
00579     }
00580 
00581   for ( it = mDeletedIncidences.begin(); it != mDeletedIncidences.end(); ++it )
00582     if ( it.key()->uid() == uid ) {
00583       mDeletedIncidences.remove( it );
00584       break;
00585     }
00586 }
00587 
00588 void ResourceCached::enableChangeNotification()
00589 {
00590   mCalendar.registerObserver( this );
00591 }
00592 
00593 void ResourceCached::disableChangeNotification()
00594 {
00595   mCalendar.unregisterObserver( this );
00596 }
00597 
00598 void ResourceCached::slotReload()
00599 {
00600   if ( !isActive() ) return;
00601 
00602   kdDebug(5800) << "ResourceCached::slotReload()" << endl;
00603 
00604   load();
00605 }
00606 
00607 void ResourceCached::slotSave()
00608 {
00609   if ( !isActive() ) return;
00610 
00611   kdDebug(5800) << "ResourceCached::slotSave()" << endl;
00612 
00613   save();
00614 }
00615 
00616 void ResourceCached::checkForAutomaticSave()
00617 {
00618   if ( mSavePolicy == SaveAlways )  {
00619     kdDebug(5800) << "ResourceCached::checkForAutomaticSave(): save now" << endl;
00620     mSaveTimer.start( 1 * 1000, true ); // 1 second
00621   } else if ( mSavePolicy == SaveDelayed ) {
00622     kdDebug(5800) << "ResourceCached::checkForAutomaticSave(): save delayed"
00623               << endl;
00624     mSaveTimer.start( 15 * 1000, true ); // 15 seconds
00625   }
00626 }
00627 
00628 bool ResourceCached::checkForReload()
00629 {
00630   if ( mReloadPolicy == ReloadNever ) return false;
00631   if ( mReloadPolicy == ReloadOnStartup ) return !mReloaded;
00632   return true;
00633 }
00634 
00635 bool ResourceCached::checkForSave()
00636 {
00637   if ( mSavePolicy == SaveNever ) return false;
00638   return true;
00639 }
00640 
00641 void ResourceCached::addInfoText( QString &txt ) const
00642 {
00643   if ( mLastLoad.isValid() ) {
00644     txt += "<br>";
00645     txt += i18n("Last loaded: %1")
00646            .arg( KGlobal::locale()->formatDateTime( mLastLoad ) );
00647   }
00648   if ( mLastSave.isValid() ) {
00649     txt += "<br>";
00650     txt += i18n("Last saved: %1")
00651            .arg( KGlobal::locale()->formatDateTime( mLastSave ) );
00652   }
00653 }
00654 
00655 void ResourceCached::doClose()
00656 {
00657   mCalendar.close();
00658 }
00659 
00660 bool ResourceCached::doOpen()
00661 {
00662   kdDebug(5800) << "Opening resource " << resourceName() << endl;
00663   return true;
00664 }
00665 
00666 void KCal::ResourceCached::setOwner( const Person &owner )
00667 {
00668   mCalendar.setOwner( owner );
00669 }
00670 
00671 const Person & KCal::ResourceCached::getOwner() const
00672 {
00673   return mCalendar.getOwner();
00674 }
00675 
00676 #include "resourcecached.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys