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