libkcal

resourcecached.cpp

Go to the documentation of this file.
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 // probably not really efficient, but...it works for now.
00159 bool ResourceCached::deleteEvent( Event *event )
00160 {
00161   kdDebug(5800) << "ResourceCached::deleteEvent" << endl;
00162 
00163   return mCalendar.deleteEvent( event );
00164 }
00165 
00166 
00167 Event *ResourceCached::event( const QString &uid )
00168 {
00169   return mCalendar.event( uid );
00170 }
00171 
00172 Event::List ResourceCached::rawEventsForDate( const QDate &qd,
00173                                               EventSortField sortField,
00174                                               SortDirection sortDirection )
00175 {
00176   Event::List list = mCalendar.rawEventsForDate( qd, sortField, sortDirection );
00177 
00178   return list;
00179 }
00180 
00181 Event::List ResourceCached::rawEvents( const QDate &start, const QDate &end,
00182                                        bool inclusive )
00183 {
00184   return mCalendar.rawEvents( start, end, inclusive );
00185 }
00186 
00187 Event::List ResourceCached::rawEventsForDate( const QDateTime &qdt )
00188 {
00189   return mCalendar.rawEventsForDate( qdt.date() );
00190 }
00191 
00192 Event::List ResourceCached::rawEvents( EventSortField sortField, SortDirection sortDirection )
00193 {
00194   return mCalendar.rawEvents( sortField, sortDirection );
00195 }
00196 
00197 bool ResourceCached::addTodo( Todo *todo )
00198 {
00199   return mCalendar.addTodo( todo );
00200 }
00201 
00202 bool ResourceCached::deleteTodo( Todo *todo )
00203 {
00204   return mCalendar.deleteTodo( todo );
00205 }
00206 
00207 bool ResourceCached::deleteJournal( Journal *journal )
00208 {
00209   return mCalendar.deleteJournal( journal );
00210 }
00211 
00212 
00213 Todo::List ResourceCached::rawTodos( TodoSortField sortField, SortDirection sortDirection )
00214 {
00215   return mCalendar.rawTodos( sortField, sortDirection );
00216 }
00217 
00218 Todo *ResourceCached::todo( const QString &uid )
00219 {
00220   return mCalendar.todo( uid );
00221 }
00222 
00223 Todo::List ResourceCached::rawTodosForDate( const QDate &date )
00224 {
00225   return mCalendar.rawTodosForDate( date );
00226 }
00227 
00228 
00229 bool ResourceCached::addJournal( Journal *journal )
00230 {
00231   kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
00232 
00233   return mCalendar.addJournal( journal );
00234 }
00235 
00236 Journal *ResourceCached::journal( const QString &uid )
00237 {
00238   return mCalendar.journal( uid );
00239 }
00240 
00241 Journal::List ResourceCached::rawJournals( JournalSortField sortField, SortDirection sortDirection )
00242 {
00243   return mCalendar.rawJournals( sortField, sortDirection );
00244 }
00245 
00246 Journal::List ResourceCached::rawJournalsForDate( const QDate &date )
00247 {
00248   return mCalendar.rawJournalsForDate( date );
00249 }
00250 
00251 
00252 Alarm::List ResourceCached::alarmsTo( const QDateTime &to )
00253 {
00254   return mCalendar.alarmsTo( to );
00255 }
00256 
00257 Alarm::List ResourceCached::alarms( const QDateTime &from, const QDateTime &to )
00258 {
00259   // kdDebug(5800) << "ResourceCached::alarms(" << from.toString() << " - " << to.toString() << ")\n";
00260   return mCalendar.alarms( from, to );
00261 }
00262 
00263 
00264 void ResourceCached::setTimeZoneId( const QString& tzid )
00265 {
00266   mCalendar.setTimeZoneId( tzid );
00267 }
00268 
00269 QString ResourceCached::timeZoneId() const
00270 {
00271   return mCalendar.timeZoneId();
00272 }
00273 
00274 void ResourceCached::clearChanges()
00275 {
00276   mAddedIncidences.clear();
00277   mChangedIncidences.clear();
00278   mDeletedIncidences.clear();
00279 }
00280 
00281 void ResourceCached::loadCache()
00282 {
00283   setIdMapperIdentifier();
00284   mIdMapper.load();
00285 
00286   if ( KStandardDirs::exists( cacheFile() ) ) {
00287     mCalendar.load( cacheFile() );
00288     if ( readOnly() ) {
00289       Incidence::List incidences( rawIncidences() );
00290       Incidence::List::Iterator it;
00291       for ( it = incidences.begin(); it != incidences.end(); ++it ) {
00292         (*it)->setReadOnly( true );
00293       }
00294     }
00295   }
00296 }
00297 
00298 void ResourceCached::saveCache()
00299 {
00300   kdDebug(5800) << "ResourceCached::saveCache(): " << cacheFile() << endl;
00301 
00302   setIdMapperIdentifier();
00303   mIdMapper.save();
00304 
00305   mCalendar.save( cacheFile() );
00306 }
00307 
00308 void ResourceCached::setIdMapperIdentifier()
00309 {
00310   mIdMapper.setIdentifier( type() + "_" + identifier() );
00311 }
00312 
00313 void ResourceCached::clearCache()
00314 {
00315   mCalendar.close();
00316 }
00317 
00318 void ResourceCached::cleanUpEventCache( const Event::List &eventList )
00319 {
00320   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00321 
00322   if ( KStandardDirs::exists( cacheFile() ) )
00323     calendar.load( cacheFile() );
00324   else
00325     return;
00326 
00327   Event::List list = calendar.events();
00328   Event::List::ConstIterator cacheIt, it;
00329   for ( cacheIt = list.begin(); cacheIt != list.end(); ++cacheIt ) {
00330     bool found = false;
00331     for ( it = eventList.begin(); it != eventList.end(); ++it ) {
00332       if ( (*it)->uid() == (*cacheIt)->uid() )
00333         found = true;
00334     }
00335 
00336     if ( !found ) {
00337       mIdMapper.removeRemoteId( mIdMapper.remoteId( (*cacheIt)->uid() ) );
00338       Event *event = mCalendar.event( (*cacheIt)->uid() );
00339       if ( event )
00340         mCalendar.deleteEvent( event );
00341     }
00342   }
00343 
00344   calendar.close();
00345 }
00346 
00347 void ResourceCached::cleanUpTodoCache( const Todo::List &todoList )
00348 {
00349   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00350 
00351   if ( KStandardDirs::exists( cacheFile() ) )
00352     calendar.load( cacheFile() );
00353   else
00354     return;
00355 
00356   Todo::List list = calendar.todos();
00357   Todo::List::ConstIterator cacheIt, it;
00358   for ( cacheIt = list.begin(); cacheIt != list.end(); ++cacheIt ) {
00359 
00360     bool found = false;
00361     for ( it = todoList.begin(); it != todoList.end(); ++it ) {
00362       if ( (*it)->uid() == (*cacheIt)->uid() )
00363         found = true;
00364     }
00365 
00366     if ( !found ) {
00367       mIdMapper.removeRemoteId( mIdMapper.remoteId( (*cacheIt)->uid() ) );
00368       Todo *todo = mCalendar.todo( (*cacheIt)->uid() );
00369       if ( todo )
00370         mCalendar.deleteTodo( todo );
00371     }
00372   }
00373 
00374   calendar.close();
00375 }
00376 
00377 KPIM::IdMapper& ResourceCached::idMapper()
00378 {
00379   return mIdMapper;
00380 }
00381 
00382 QString ResourceCached::cacheFile() const
00383 {
00384   return locateLocal( "cache", "kcal/kresources/" + identifier() );
00385 }
00386 
00387 QString ResourceCached::changesCacheFile( const QString &type ) const
00388 {
00389   return locateLocal( "cache", "kcal/changescache/" + identifier() + "_" + type );
00390 }
00391 
00392 void ResourceCached::saveChangesCache( const QMap<Incidence*, bool> &map, const QString &type )
00393 {
00394   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00395 
00396   bool isEmpty = true;
00397   QMap<Incidence *,bool>::ConstIterator it;
00398   for ( it = map.begin(); it != map.end(); ++it ) {
00399     isEmpty = false;
00400     calendar.addIncidence( it.key()->clone() );
00401   }
00402 
00403   if ( !isEmpty ) {
00404     calendar.save( changesCacheFile( type ) );
00405   } else {
00406     QFile file( changesCacheFile( type ) );
00407     file.remove();
00408   }
00409 
00410   calendar.close();
00411 }
00412 
00413 void ResourceCached::saveChangesCache()
00414 {
00415   saveChangesCache( mAddedIncidences, "added" );
00416   saveChangesCache( mDeletedIncidences, "deleted" );
00417   saveChangesCache( mChangedIncidences, "changed" );
00418 }
00419 
00420 void ResourceCached::loadChangesCache( QMap<Incidence*, bool> &map, const QString &type )
00421 {
00422   CalendarLocal calendar ( QString::fromLatin1( "UTC" ) );
00423 
00424   if ( KStandardDirs::exists( changesCacheFile( type ) ) )
00425     calendar.load( changesCacheFile( type ) );
00426   else
00427     return;
00428 
00429   const Incidence::List list = calendar.incidences();
00430   Incidence::List::ConstIterator it;
00431   for ( it = list.begin(); it != list.end(); ++it )
00432     map.insert( (*it)->clone(), true );
00433 
00434   calendar.close();
00435 }
00436 
00437 void ResourceCached::loadChangesCache()
00438 {
00439   loadChangesCache( mAddedIncidences, "added" );
00440   loadChangesCache( mDeletedIncidences, "deleted" );
00441   loadChangesCache( mChangedIncidences, "changed" );
00442 }
00443 
00444 void ResourceCached::calendarIncidenceAdded( Incidence *i )
00445 {
00446 #if 1
00447   kdDebug(5800) << "ResourceCached::calendarIncidenceAdded(): "
00448             << i->uid() << endl;
00449 #endif
00450 
00451   QMap<Incidence *,bool>::ConstIterator it;
00452   it = mAddedIncidences.find( i );
00453   if ( it == mAddedIncidences.end() ) {
00454     mAddedIncidences.insert( i, true );
00455   }
00456 
00457   checkForAutomaticSave();
00458 }
00459 
00460 void ResourceCached::calendarIncidenceChanged( Incidence *i )
00461 {
00462 #if 1
00463   kdDebug(5800) << "ResourceCached::calendarIncidenceChanged(): "
00464             << i->uid() << endl;
00465 #endif
00466 
00467   QMap<Incidence *,bool>::ConstIterator it;
00468   it = mChangedIncidences.find( i );
00469   // FIXME: If you modify an added incidence, there's no need to add it to mChangedIncidences!
00470   if ( it == mChangedIncidences.end() ) {
00471     mChangedIncidences.insert( i, true );
00472   }
00473 
00474   checkForAutomaticSave();
00475 }
00476 
00477 void ResourceCached::calendarIncidenceDeleted( Incidence *i )
00478 {
00479 #if 1
00480   kdDebug(5800) << "ResourceCached::calendarIncidenceDeleted(): "
00481             << i->uid() << endl;
00482 #endif
00483 
00484   QMap<Incidence *,bool>::ConstIterator it;
00485   it = mDeletedIncidences.find( i );
00486   if ( it == mDeletedIncidences.end() ) {
00487     mDeletedIncidences.insert( i, true );
00488   }
00489 
00490   checkForAutomaticSave();
00491 }
00492 
00493 Incidence::List ResourceCached::addedIncidences() const
00494 {
00495   Incidence::List added;
00496   QMap<Incidence *,bool>::ConstIterator it;
00497   for( it = mAddedIncidences.begin(); it != mAddedIncidences.end(); ++it ) {
00498     added.append( it.key() );
00499   }
00500   return added;
00501 }
00502 
00503 Incidence::List ResourceCached::changedIncidences() const
00504 {
00505   Incidence::List changed;
00506   QMap<Incidence *,bool>::ConstIterator it;
00507   for( it = mChangedIncidences.begin(); it != mChangedIncidences.end(); ++it ) {
00508     changed.append( it.key() );
00509   }
00510   return changed;
00511 }
00512 
00513 Incidence::List ResourceCached::deletedIncidences() const
00514 {
00515   Incidence::List deleted;
00516   QMap<Incidence *,bool>::ConstIterator it;
00517   for( it = mDeletedIncidences.begin(); it != mDeletedIncidences.end(); ++it ) {
00518     deleted.append( it.key() );
00519   }
00520   return deleted;
00521 }
00522 
00523 Incidence::List ResourceCached::allChanges() const
00524 {
00525   Incidence::List changes;
00526   QMap<Incidence *,bool>::ConstIterator it;
00527   for( it = mAddedIncidences.begin(); it != mAddedIncidences.end(); ++it ) {
00528     changes.append( it.key() );
00529   }
00530   for( it = mChangedIncidences.begin(); it != mChangedIncidences.end(); ++it ) {
00531     changes.append( it.key() );
00532   }
00533   for( it = mDeletedIncidences.begin(); it != mDeletedIncidences.end(); ++it ) {
00534     changes.append( it.key() );
00535   }
00536   return changes;
00537 }
00538 
00539 bool ResourceCached::hasChanges() const
00540 {
00541   return !( mAddedIncidences.isEmpty() && mChangedIncidences.isEmpty() &&
00542             mDeletedIncidences.isEmpty() );
00543 }
00544 
00545 void ResourceCached::clearChange( Incidence *incidence )
00546 {
00547   clearChange( incidence->uid() );
00548 }
00549 
00550 void ResourceCached::clearChange( const QString &uid )
00551 {
00552   QMap<Incidence*, bool>::Iterator it;
00553 
00554   for ( it = mAddedIncidences.begin(); it != mAddedIncidences.end(); ++it )
00555     if ( it.key()->uid() == uid ) {
00556       mAddedIncidences.remove( it );
00557       break;
00558     }
00559 
00560   for ( it = mChangedIncidences.begin(); it != mChangedIncidences.end(); ++it )
00561     if ( it.key()->uid() == uid ) {
00562       mChangedIncidences.remove( it );
00563       break;
00564     }
00565 
00566   for ( it = mDeletedIncidences.begin(); it != mDeletedIncidences.end(); ++it )
00567     if ( it.key()->uid() == uid ) {
00568       mDeletedIncidences.remove( it );
00569       break;
00570     }
00571 }
00572 
00573 void ResourceCached::enableChangeNotification()
00574 {
00575   mCalendar.registerObserver( this );
00576 }
00577 
00578 void ResourceCached::disableChangeNotification()
00579 {
00580   mCalendar.unregisterObserver( this );
00581 }
00582 
00583 void ResourceCached::slotReload()
00584 {
00585   if ( !isActive() ) return;
00586 
00587   kdDebug(5800) << "ResourceCached::slotReload()" << endl;
00588 
00589   load();
00590 }
00591 
00592 void ResourceCached::slotSave()
00593 {
00594   if ( !isActive() ) return;
00595 
00596   kdDebug(5800) << "ResourceCached::slotSave()" << endl;
00597 
00598   save();
00599 }
00600 
00601 void ResourceCached::checkForAutomaticSave()
00602 {
00603   if ( mSavePolicy == SaveAlways )  {
00604     kdDebug(5800) << "ResourceCached::checkForAutomaticSave(): save now" << endl;
00605     mSaveTimer.start( 1 * 1000, true ); // 1 second
00606   } else if ( mSavePolicy == SaveDelayed ) {
00607     kdDebug(5800) << "ResourceCached::checkForAutomaticSave(): save delayed"
00608               << endl;
00609     mSaveTimer.start( 15 * 1000, true ); // 15 seconds
00610   }
00611 }
00612 
00613 bool ResourceCached::checkForReload()
00614 {
00615   if ( mReloadPolicy == ReloadNever ) return false;
00616   if ( mReloadPolicy == ReloadOnStartup ) return !mReloaded;
00617   return true;
00618 }
00619 
00620 bool ResourceCached::checkForSave()
00621 {
00622   if ( mSavePolicy == SaveNever ) return false;
00623   return true;
00624 }
00625 
00626 void ResourceCached::addInfoText( QString &txt ) const
00627 {
00628   if ( mLastLoad.isValid() ) {
00629     txt += "<br>";
00630     txt += i18n("Last loaded: %1")
00631            .arg( KGlobal::locale()->formatDateTime( mLastLoad ) );
00632   }
00633   if ( mLastSave.isValid() ) {
00634     txt += "<br>";
00635     txt += i18n("Last saved: %1")
00636            .arg( KGlobal::locale()->formatDateTime( mLastSave ) );
00637   }
00638 }
00639 
00640 void ResourceCached::doClose()
00641 {
00642   mCalendar.close();
00643 }
00644 
00645 bool ResourceCached::doOpen()
00646 {
00647   kdDebug(5800) << "Opening resource " << resourceName() << endl;
00648   return true;
00649 }
00650 
00651 void KCal::ResourceCached::setOwner( const Person &owner )
00652 {
00653   mCalendar.setOwner( owner );
00654 }
00655 
00656 const Person & KCal::ResourceCached::getOwner() const
00657 {
00658   return mCalendar.getOwner();
00659 }
00660 
00661 #include "resourcecached.moc"