• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

KCal Library

resourcelocaldir.cpp

00001 /*
00002   This file is part of the kcal library.
00003 
00004   Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
00005   Copyright (c) 2009 Sergio Martins <iamsergio@gmail.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 */
00022 
00023 #include "resourcelocaldir.h"
00024 #include "resourcelocaldir_p.h"
00025 #include "calendarlocal.h"
00026 #include "incidence.h"
00027 #include "event.h"
00028 #include "todo.h"
00029 #include "journal.h"
00030 #include "freebusy.h"
00031 
00032 #include "kresources/configwidget.h"
00033 
00034 #include "assignmentvisitor_p.h"
00035 #include "comparisonvisitor_p.h"
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038 #include <kconfig.h>
00039 #include <kstandarddirs.h>
00040 #include <kconfiggroup.h>
00041 
00042 #include <QtCore/QString>
00043 #include <QtCore/QDir>
00044 #include <QtCore/QFileInfo>
00045 
00046 #include <typeinfo>
00047 #include <stdlib.h>
00048 
00049 #include "resourcelocaldir.moc"
00050 #include "resourcelocaldir_p.moc"
00051 
00052 using namespace KCal;
00053 
00054 ResourceLocalDir::ResourceLocalDir()
00055   : ResourceCached(), d( new KCal::ResourceLocalDir::Private( this ) )
00056 {
00057   d->init();
00058 }
00059 
00060 ResourceLocalDir::ResourceLocalDir( const KConfigGroup &group )
00061   : ResourceCached( group ), d( new KCal::ResourceLocalDir::Private( this ) )
00062 {
00063   readConfig( group );
00064   d->init();
00065 }
00066 
00067 ResourceLocalDir::ResourceLocalDir( const QString &dirName )
00068   : ResourceCached(), d( new KCal::ResourceLocalDir::Private( dirName, this ) )
00069 {
00070   d->init();
00071 }
00072 
00073 void ResourceLocalDir::readConfig( const KConfigGroup &group )
00074 {
00075   QString url = group.readPathEntry( "CalendarURL", QString() );
00076   d->mURL = KUrl( url );
00077 }
00078 
00079 void ResourceLocalDir::writeConfig( KConfigGroup &group )
00080 {
00081   kDebug();
00082 
00083   ResourceCalendar::writeConfig( group );
00084 
00085   group.writePathEntry( "CalendarURL", d->mURL.prettyUrl() );
00086 }
00087 
00088 void ResourceLocalDir::Private::init( )
00089 {
00090   mResource->setType( "dir" );
00091 
00092   mResource->setSavePolicy( SaveDelayed );
00093 
00094   connect( &mDirWatch, SIGNAL( dirty( const QString & ) ),
00095            this, SLOT( updateIncidenceInCalendar( const QString & ) ) );
00096   connect( &mDirWatch, SIGNAL( created( const QString & ) ),
00097            this, SLOT( addIncidenceToCalendar( const QString & ) ) );
00098   connect( &mDirWatch, SIGNAL( deleted( const QString & ) ),
00099            this, SLOT( deleteIncidenceFromCalendar( const QString & ) ) );
00100 
00101   connect ( this, SIGNAL(resourceChanged( ResourceCalendar *)),
00102             mResource, SIGNAL(resourceChanged( ResourceCalendar *)) );
00103 
00104   mLock = new KABC::Lock( mURL.path() );
00105 
00106   mDirWatch.addDir( mURL.path(), KDirWatch::WatchFiles );
00107   mDirWatch.startScan();
00108 }
00109 
00110 ResourceLocalDir::~ResourceLocalDir()
00111 {
00112   close();
00113 
00114   delete d->mLock;
00115   delete d;
00116 }
00117 
00118 bool ResourceLocalDir::doOpen()
00119 {
00120   QFileInfo dirInfo( d->mURL.path() );
00121   return dirInfo.isDir() && dirInfo.isReadable() &&
00122     ( dirInfo.isWritable() || readOnly() );
00123 }
00124 
00125 bool ResourceLocalDir::doLoad( bool )
00126 {
00127   kDebug();
00128 
00129   calendar()->close();
00130   QString dirName = d->mURL.path();
00131 
00132   if ( !( KStandardDirs::exists( dirName ) || KStandardDirs::exists( dirName + '/' ) ) ) {
00133     kDebug() << "Directory '" << dirName << "' doesn't exist yet. Creating it.";
00134 
00135     // Create the directory. Use 0775 to allow group-writable if the umask
00136     // allows it (permissions will be 0775 & ~umask). This is desired e.g. for
00137     // group-shared directories!
00138     return KStandardDirs::makeDir( dirName, 0775 );
00139   }
00140 
00141   // The directory exists. Now try to open (the files in) it.
00142   kDebug() << dirName;
00143   QFileInfo dirInfo( dirName );
00144   if ( !( dirInfo.isDir() && dirInfo.isReadable() &&
00145           ( dirInfo.isWritable() || readOnly() ) ) ) {
00146     return false;
00147   }
00148 
00149   QDir dir( dirName );
00150   const QStringList entries = dir.entryList( QDir::Files | QDir::Readable );
00151 
00152   bool success = true;
00153 
00154   foreach ( const QString &entry, entries ) {
00155     if ( d->isTempFile( entry ) ) {
00156       continue;  // backup or temporary file, ignore it
00157     }
00158 
00159     const QString fileName = dirName + '/' + entry;
00160     kDebug() << " read '" << fileName << "'";
00161     CalendarLocal cal( calendar()->timeSpec() );
00162     if ( !doFileLoad( cal, fileName ) ) {
00163       success = false;
00164     }
00165   }
00166 
00167   return success;
00168 }
00169 
00170 bool ResourceLocalDir::doFileLoad( CalendarLocal &cal, const QString &fileName )
00171 {
00172   return d->doFileLoad( cal, fileName, false );
00173 }
00174 
00175 bool ResourceLocalDir::doSave( bool syncCache )
00176 {
00177   Q_UNUSED( syncCache );
00178   Incidence::List list;
00179   bool success = true;
00180 
00181   list = addedIncidences();
00182   list += changedIncidences();
00183 
00184   for ( Incidence::List::iterator it = list.begin(); it != list.end(); ++it ) {
00185     if ( !doSave( *it ) ) {
00186       success = false;
00187     }
00188   }
00189 
00190   return success;
00191 }
00192 
00193 bool ResourceLocalDir::doSave( bool, Incidence *incidence )
00194 {
00195   if ( d->mDeletedIncidences.contains( incidence ) ) {
00196     d->mDeletedIncidences.removeAll( incidence );
00197     return true;
00198   }
00199 
00200   d->mDirWatch.stopScan();  // do prohibit the dirty() signal and a following reload()
00201 
00202   QString fileName = d->mURL.path() + '/' + incidence->uid();
00203   kDebug() << "writing '" << fileName << "'";
00204 
00205   CalendarLocal cal( calendar()->timeSpec() );
00206   cal.addIncidence( incidence->clone() );
00207   const bool ret = cal.save( fileName );
00208 
00209   d->mDirWatch.startScan();
00210 
00211   return ret;
00212 }
00213 
00214 KABC::Lock *ResourceLocalDir::lock()
00215 {
00216   return d->mLock;
00217 }
00218 
00219 void ResourceLocalDir::reload( const QString &file )
00220 {
00221   Q_UNUSED( file );
00222 }
00223 
00224 bool ResourceLocalDir::deleteEvent( Event *event )
00225 {
00226   kDebug();
00227   if ( d->deleteIncidenceFile( event ) ) {
00228     if ( calendar()->deleteEvent( event ) ) {
00229       d->mDeletedIncidences.append( event );
00230       return true;
00231     } else {
00232       return false;
00233     }
00234   } else {
00235     return false;
00236   }
00237 }
00238 
00239 void ResourceLocalDir::deleteAllEvents()
00240 {
00241   calendar()->deleteAllEvents();
00242 }
00243 
00244 bool ResourceLocalDir::deleteTodo( Todo *todo )
00245 {
00246   if ( d->deleteIncidenceFile( todo ) ) {
00247     if ( calendar()->deleteTodo( todo ) ) {
00248       d->mDeletedIncidences.append( todo );
00249       return true;
00250     } else {
00251       return false;
00252     }
00253   } else {
00254     return false;
00255   }
00256 }
00257 
00258 void ResourceLocalDir::deleteAllTodos()
00259 {
00260   calendar()->deleteAllTodos();
00261 }
00262 
00263 bool ResourceLocalDir::deleteJournal( Journal *journal )
00264 {
00265   if ( d->deleteIncidenceFile( journal ) ) {
00266     if ( calendar()->deleteJournal( journal ) ) {
00267       d->mDeletedIncidences.append( journal );
00268       return true;
00269     } else {
00270       return false;
00271     }
00272   } else {
00273     return false;
00274   }
00275 }
00276 
00277 void ResourceLocalDir::deleteAllJournals()
00278 {
00279   calendar()->deleteAllJournals();
00280 }
00281 
00282 void ResourceLocalDir::dump() const
00283 {
00284   ResourceCalendar::dump();
00285   kDebug() << "  Url:" << d->mURL.url();
00286 }
00287 
00288 bool ResourceLocalDir::Private::deleteIncidenceFile( Incidence *incidence )
00289 {
00290   QFile file( mURL.path() + '/' + incidence->uid() );
00291   if ( !file.exists() ) {
00292     return true;
00293   }
00294 
00295   mDirWatch.stopScan();
00296   bool removed = file.remove();
00297   mDirWatch.startScan();
00298   return removed;
00299 }
00300 
00301 bool ResourceLocalDir::Private::isTempFile( const QString &fileName ) const
00302 {
00303   return
00304     fileName.contains( QRegExp( "(~|\\.new|\\.tmp)$" ) ) ||
00305     QFileInfo( fileName ).fileName().startsWith( QLatin1String( "qt_temp." ) ) ||
00306     fileName == mURL.path();
00307 }
00308 
00309 void ResourceLocalDir::Private::addIncidenceToCalendar( const QString &file )
00310 {
00311 
00312   if ( mResource->isOpen() &&
00313        !isTempFile( file ) &&
00314        !mResource->calendar()->incidence( getUidFromFileName( file ) ) ) {
00315 
00316     CalendarLocal cal( mResource->calendar()->timeSpec() );
00317     if ( doFileLoad( cal, file, true ) ) {
00318       emit resourceChanged( mResource );
00319     }
00320   }
00321 }
00322 
00323 void ResourceLocalDir::Private::updateIncidenceInCalendar( const QString &file )
00324 {
00325   if ( mResource->isOpen() && !isTempFile( file ) ) {
00326     CalendarLocal cal( mResource->calendar()->timeSpec() );
00327     if ( doFileLoad( cal, file, true ) ) {
00328       emit resourceChanged( mResource );
00329     }
00330   }
00331 }
00332 
00333 QString ResourceLocalDir::Private::getUidFromFileName( const QString &fileName )
00334 {
00335   return QFileInfo( fileName ).fileName();
00336 }
00337 
00338 void ResourceLocalDir::Private::deleteIncidenceFromCalendar( const QString &file )
00339 {
00340 
00341   if ( mResource->isOpen() && !isTempFile( file ) ) {
00342     Incidence *inc = mResource->calendar()->incidence( getUidFromFileName( file ) );
00343 
00344     if ( inc ) {
00345       mResource->calendar()->deleteIncidence( inc );
00346       emit resourceChanged( mResource );
00347     }
00348   }
00349 }
00350 
00351 bool ResourceLocalDir::Private::doFileLoad( CalendarLocal &cal,
00352                                             const QString &fileName,
00353                                             const bool replace )
00354 {
00355   if ( !cal.load( fileName ) ) {
00356     return false;
00357   }
00358   Incidence::List incidences = cal.rawIncidences();
00359   Incidence::List::ConstIterator it;
00360   Incidence *inc;
00361   ComparisonVisitor compVisitor;
00362   AssignmentVisitor assVisitor;
00363   for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
00364     Incidence *i = *it;
00365     if ( i ) {
00366       // should we replace, and does the incidence exist in calendar?
00367       if ( replace && ( inc = mResource->calendar()->incidence( i->uid() ) ) ) {
00368         if ( compVisitor.compare( i, inc ) ) {
00369           // no need to do anything
00370           return false;
00371         } else {
00372           inc->startUpdates();
00373 
00374           bool assignResult = assVisitor.assign( inc, i );
00375 
00376           if ( assignResult ) {
00377             if ( !inc->relatedToUid().isEmpty() ) {
00378               QString uid = inc->relatedToUid();
00379               inc->setRelatedTo( mResource->calendar()->incidence( uid ) );
00380             }
00381             inc->updated();
00382             inc->endUpdates();
00383           } else {
00384             inc->endUpdates();
00385             kWarning() << "Incidence (uid=" << inc->uid()
00386                        << ", summary=" << inc->summary()
00387                        << ") changed type. Replacing it.";
00388 
00389             mResource->calendar()->deleteIncidence( inc );
00390             delete inc;
00391             mResource->calendar()->addIncidence( i->clone() );
00392           }
00393         }
00394       } else {
00395         mResource->calendar()->addIncidence( i->clone() );
00396       }
00397     }
00398   }
00399   return true;
00400 }
00401 
00402 class AssignmentVisitor::Private
00403 {
00404   public:
00405     Private() : mSource( 0 ) {}
00406 
00407   public:
00408     const IncidenceBase *mSource;
00409 };
00410 
00411 AssignmentVisitor::AssignmentVisitor() : d( new Private() )
00412 {
00413 }
00414 
00415 AssignmentVisitor::~AssignmentVisitor()
00416 {
00417   delete d;
00418 }
00419 
00420 bool AssignmentVisitor::assign( IncidenceBase *target, const IncidenceBase *source )
00421 {
00422   Q_ASSERT( target != 0 );
00423   Q_ASSERT( source != 0 );
00424 
00425   d->mSource = source;
00426 
00427   bool result = target->accept( *this );
00428 
00429   d->mSource = 0;
00430 
00431   return result;
00432 }
00433 
00434 bool AssignmentVisitor::visit( Event *event )
00435 {
00436   Q_ASSERT( event != 0 );
00437 
00438   const Event *source = dynamic_cast<const Event*>( d->mSource );
00439   if ( source == 0 ) {
00440     kError(5800) << "Type mismatch: source is" << d->mSource->type()
00441                  << "target is" << event->type();
00442     return false;
00443   }
00444 
00445   *event = *source;
00446   return true;
00447 }
00448 
00449 bool AssignmentVisitor::visit( Todo *todo )
00450 {
00451   Q_ASSERT( todo != 0 );
00452 
00453   const Todo *source = dynamic_cast<const Todo*>( d->mSource );
00454   if ( source == 0 ) {
00455     kError(5800) << "Type mismatch: source is" << d->mSource->type()
00456                  << "target is" << todo->type();
00457     return false;
00458   }
00459 
00460   *todo = *source;
00461   return true;
00462 }
00463 
00464 bool AssignmentVisitor::visit( Journal *journal )
00465 {
00466   Q_ASSERT( journal != 0 );
00467 
00468   const Journal *source = dynamic_cast<const Journal*>( d->mSource );
00469   if ( source == 0 ) {
00470     kError(5800) << "Type mismatch: source is" << d->mSource->type()
00471                  << "target is" << journal->type();
00472     return false;
00473   }
00474 
00475   *journal = *source;
00476   return true;
00477 }
00478 
00479 bool AssignmentVisitor::visit( FreeBusy *freebusy )
00480 {
00481   Q_ASSERT( freebusy != 0 );
00482 
00483   const FreeBusy *source = dynamic_cast<const FreeBusy*>( d->mSource );
00484   if ( source == 0 ) {
00485     kError(5800) << "Type mismatch: source is" << d->mSource->type()
00486                  << "target is" << freebusy->type();
00487     return false;
00488   }
00489 
00490   *freebusy = *source;
00491   return true;
00492 }
00493 
00494 class ComparisonVisitor::Private
00495 {
00496   public:
00497     Private() : mReference( 0 ) {}
00498 
00499   public:
00500     const IncidenceBase *mReference;
00501 };
00502 
00503 ComparisonVisitor::ComparisonVisitor() : d( new Private() )
00504 {
00505 }
00506 
00507 ComparisonVisitor::~ComparisonVisitor()
00508 {
00509   delete d;
00510 }
00511 
00512 bool ComparisonVisitor::compare( IncidenceBase *incidence, const IncidenceBase *reference )
00513 {
00514   d->mReference = reference;
00515 
00516   const bool result = incidence ? incidence->accept( *this ) : reference == 0;
00517 
00518   d->mReference = 0;
00519 
00520   return result;
00521 }
00522 
00523 bool ComparisonVisitor::visit( Event *event )
00524 {
00525   Q_ASSERT( event != 0 );
00526 
00527   const Event *refEvent = dynamic_cast<const Event*>( d->mReference );
00528   if ( refEvent ) {
00529     return *event == *refEvent;
00530   } else {
00531     // refEvent is no Event and thus cannot be equal to event
00532     return false;
00533   }
00534 }
00535 
00536 bool ComparisonVisitor::visit( Todo *todo )
00537 {
00538   Q_ASSERT( todo != 0 );
00539 
00540   const Todo *refTodo = dynamic_cast<const Todo*>( d->mReference );
00541   if ( refTodo ) {
00542     return *todo == *refTodo;
00543   } else {
00544     // refTodo is no Todo and thus cannot be equal to todo
00545     return false;
00546   }
00547 }
00548 
00549 bool ComparisonVisitor::visit( Journal *journal )
00550 {
00551   Q_ASSERT( journal != 0 );
00552 
00553   const Journal *refJournal = dynamic_cast<const Journal*>( d->mReference );
00554   if ( refJournal ) {
00555     return *journal == *refJournal;
00556   } else {
00557     // refJournal is no Journal and thus cannot be equal to journal
00558     return false;
00559   }
00560 }
00561 
00562 bool ComparisonVisitor::visit( FreeBusy *freebusy )
00563 {
00564   Q_ASSERT( freebusy != 0 );
00565 
00566   const FreeBusy *refFreeBusy = dynamic_cast<const FreeBusy*>( d->mReference );
00567   if ( refFreeBusy ) {
00568     return *freebusy == *refFreeBusy;
00569   } else {
00570     // refFreeBusy is no FreeBusy and thus cannot be equal to freebusy
00571     return false;
00572   }
00573 }
00574 

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.7.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal