00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00031 #include "kresources/configwidget.h"
00032
00033 #include <kcal/assignmentvisitor.h>
00034 #include <kcal/comparisonvisitor.h>
00035 #include <kdebug.h>
00036 #include <klocale.h>
00037 #include <kconfig.h>
00038 #include <kstandarddirs.h>
00039 #include <kconfiggroup.h>
00040
00041 #include <QtCore/QString>
00042 #include <QtCore/QDir>
00043 #include <QtCore/QFileInfo>
00044
00045 #include <typeinfo>
00046 #include <stdlib.h>
00047
00048 #include "resourcelocaldir.moc"
00049 #include "resourcelocaldir_p.moc"
00050
00051 using namespace KCal;
00052
00053 ResourceLocalDir::ResourceLocalDir()
00054 : ResourceCached(), d( new KCal::ResourceLocalDir::Private( this ) )
00055 {
00056 d->init();
00057 }
00058
00059 ResourceLocalDir::ResourceLocalDir( const KConfigGroup &group )
00060 : ResourceCached( group ), d( new KCal::ResourceLocalDir::Private( this ) )
00061 {
00062 readConfig( group );
00063 d->init();
00064 }
00065
00066 ResourceLocalDir::ResourceLocalDir( const QString &dirName )
00067 : ResourceCached(), d( new KCal::ResourceLocalDir::Private( dirName, this ) )
00068 {
00069 d->init();
00070 }
00071
00072 void ResourceLocalDir::readConfig( const KConfigGroup &group )
00073 {
00074 QString url = group.readPathEntry( "CalendarURL", QString() );
00075 d->mURL = KUrl( url );
00076 }
00077
00078 void ResourceLocalDir::writeConfig( KConfigGroup &group )
00079 {
00080 kDebug();
00081
00082 ResourceCalendar::writeConfig( group );
00083
00084 group.writePathEntry( "CalendarURL", d->mURL.prettyUrl() );
00085 }
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
00111 ResourceLocalDir::~ResourceLocalDir()
00112 {
00113 close();
00114
00115 delete d->mLock;
00116 delete d;
00117 }
00118
00119 bool ResourceLocalDir::doOpen()
00120 {
00121 QFileInfo dirInfo( d->mURL.path() );
00122 return dirInfo.isDir() && dirInfo.isReadable() &&
00123 ( dirInfo.isWritable() || readOnly() );
00124 }
00125
00126 bool ResourceLocalDir::doLoad( bool )
00127 {
00128 kDebug();
00129
00130 calendar()->close();
00131 QString dirName = d->mURL.path();
00132
00133 if ( !( KStandardDirs::exists( dirName ) || KStandardDirs::exists( dirName + '/' ) ) ) {
00134 kDebug() << "Directory '" << dirName << "' doesn't exist yet. Creating it.";
00135
00136
00137
00138
00139 return KStandardDirs::makeDir( dirName, 0775 );
00140 }
00141
00142
00143 kDebug() << dirName;
00144 QFileInfo dirInfo( dirName );
00145 if ( !( dirInfo.isDir() && dirInfo.isReadable() &&
00146 ( dirInfo.isWritable() || readOnly() ) ) ) {
00147 return false;
00148 }
00149
00150 QDir dir( dirName );
00151 const QStringList entries = dir.entryList( QDir::Files | QDir::Readable );
00152
00153 bool success = true;
00154
00155 foreach ( const QString &entry, entries ) {
00156 if ( d->isTempFile( entry ) ) {
00157 continue;
00158 }
00159
00160 const QString fileName = dirName + '/' + entry;
00161 kDebug() << " read '" << fileName << "'";
00162 CalendarLocal cal( calendar()->timeSpec() );
00163 if ( !doFileLoad( cal, fileName ) ) {
00164 success = false;
00165 }
00166 }
00167
00168 return success;
00169 }
00170
00171 bool ResourceLocalDir::doFileLoad( CalendarLocal &cal, const QString &fileName )
00172 {
00173 return d->doFileLoad( cal, fileName, false );
00174 }
00175
00176 bool ResourceLocalDir::doSave( bool syncCache )
00177 {
00178 Q_UNUSED( syncCache );
00179 Incidence::List list;
00180 bool success = true;
00181
00182 list = addedIncidences();
00183 list += changedIncidences();
00184
00185 for ( Incidence::List::iterator it = list.begin(); it != list.end(); ++it ) {
00186 if ( !doSave( *it ) ) {
00187 success = false;
00188 }
00189 }
00190
00191 return success;
00192 }
00193
00194 bool ResourceLocalDir::doSave( bool, Incidence *incidence )
00195 {
00196 if ( d->mDeletedIncidences.contains( incidence ) ) {
00197 d->mDeletedIncidences.removeAll( incidence );
00198 return true;
00199 }
00200
00201 d->mDirWatch.stopScan();
00202
00203 QString fileName = d->mURL.path() + '/' + incidence->uid();
00204 kDebug() << "writing '" << fileName << "'";
00205
00206 CalendarLocal cal( calendar()->timeSpec() );
00207 cal.addIncidence( incidence->clone() );
00208 const bool ret = cal.save( fileName );
00209
00210 d->mDirWatch.startScan();
00211
00212 return ret;
00213 }
00214
00215 KABC::Lock *ResourceLocalDir::lock()
00216 {
00217 return d->mLock;
00218 }
00219
00220 void ResourceLocalDir::reload( const QString &file )
00221 {
00222 Q_UNUSED( file );
00223 }
00224
00225 bool ResourceLocalDir::deleteEvent( Event *event )
00226 {
00227 kDebug();
00228 if ( d->deleteIncidenceFile( event ) ) {
00229 if ( calendar()->deleteEvent( event ) ) {
00230 d->mDeletedIncidences.append( event );
00231 return true;
00232 } else {
00233 return false;
00234 }
00235 } else {
00236 return false;
00237 }
00238 }
00239
00240 void ResourceLocalDir::deleteAllEvents()
00241 {
00242 calendar()->deleteAllEvents();
00243 }
00244
00245 bool ResourceLocalDir::deleteTodo( Todo *todo )
00246 {
00247 if ( d->deleteIncidenceFile( todo ) ) {
00248 if ( calendar()->deleteTodo( todo ) ) {
00249 d->mDeletedIncidences.append( todo );
00250 return true;
00251 } else {
00252 return false;
00253 }
00254 } else {
00255 return false;
00256 }
00257 }
00258
00259 void ResourceLocalDir::deleteAllTodos()
00260 {
00261 calendar()->deleteAllTodos();
00262 }
00263
00264 bool ResourceLocalDir::deleteJournal( Journal *journal )
00265 {
00266 if ( d->deleteIncidenceFile( journal ) ) {
00267 if ( calendar()->deleteJournal( journal ) ) {
00268 d->mDeletedIncidences.append( journal );
00269 return true;
00270 } else {
00271 return false;
00272 }
00273 } else {
00274 return false;
00275 }
00276 }
00277
00278 void ResourceLocalDir::deleteAllJournals()
00279 {
00280 calendar()->deleteAllJournals();
00281 }
00282
00283 void ResourceLocalDir::dump() const
00284 {
00285 ResourceCalendar::dump();
00286 kDebug() << " Url:" << d->mURL.url();
00287 }
00288
00289
00290 bool ResourceLocalDir::Private::deleteIncidenceFile( Incidence *incidence )
00291 {
00292 QFile file( mURL.path() + '/' + incidence->uid() );
00293 if ( !file.exists() ) {
00294 return true;
00295 }
00296
00297 mDirWatch.stopScan();
00298 bool removed = file.remove();
00299 mDirWatch.startScan();
00300 return removed;
00301 }
00302
00303 bool ResourceLocalDir::Private::isTempFile( const QString &fileName ) const
00304 {
00305 return
00306 fileName.contains( QRegExp( "(~|\\.new|\\.tmp)$" ) ) ||
00307 QFileInfo( fileName ).fileName().startsWith( QLatin1String( "qt_temp." ) ) ||
00308 fileName == mURL.path();
00309 }
00310
00311 void ResourceLocalDir::Private::addIncidenceToCalendar( const QString &file )
00312 {
00313
00314 if ( mResource->isOpen() &&
00315 !isTempFile( file ) &&
00316 !mResource->calendar()->incidence( getUidFromFileName( file ) ) ) {
00317
00318 CalendarLocal cal( mResource->calendar()->timeSpec() );
00319 if ( doFileLoad( cal, file, true ) ) {
00320 emit resourceChanged( mResource );
00321 }
00322 }
00323 }
00324
00325 void ResourceLocalDir::Private::updateIncidenceInCalendar( const QString &file )
00326 {
00327 if ( mResource->isOpen() && !isTempFile( file ) ) {
00328 CalendarLocal cal( mResource->calendar()->timeSpec() );
00329 if ( doFileLoad( cal, file, true ) ) {
00330 emit resourceChanged( mResource );
00331 }
00332 }
00333 }
00334
00335 QString ResourceLocalDir::Private::getUidFromFileName( const QString &fileName )
00336 {
00337 return QFileInfo( fileName ).fileName();
00338 }
00339
00340 void ResourceLocalDir::Private::deleteIncidenceFromCalendar( const QString &file )
00341 {
00342
00343 if ( mResource->isOpen() && !isTempFile( file ) ) {
00344 Incidence *inc = mResource->calendar()->incidence( getUidFromFileName( file ) );
00345
00346 if ( inc ) {
00347 mResource->calendar()->deleteIncidence( inc );
00348 emit resourceChanged( mResource );
00349 }
00350 }
00351 }
00352
00353 bool ResourceLocalDir::Private::doFileLoad( CalendarLocal &cal,
00354 const QString &fileName,
00355 const bool replace )
00356 {
00357 if ( !cal.load( fileName ) ) {
00358 return false;
00359 }
00360 Incidence::List incidences = cal.rawIncidences();
00361 Incidence::List::ConstIterator it;
00362 Incidence *inc;
00363 ComparisonVisitor compVisitor;
00364 AssignmentVisitor assVisitor;
00365 for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
00366 Incidence *i = *it;
00367 if ( i ) {
00368
00369 if ( replace && ( inc = mResource->calendar()->incidence( i->uid() ) ) ) {
00370 if ( compVisitor.compare( i, inc ) ) {
00371
00372 return false;
00373 } else {
00374 inc->startUpdates();
00375
00376 bool assignResult = assVisitor.assign( inc, i );
00377
00378 if ( assignResult ) {
00379 if ( !inc->relatedToUid().isEmpty() ) {
00380 QString uid = inc->relatedToUid();
00381 inc->setRelatedTo( mResource->calendar()->incidence( uid ) );
00382 }
00383 inc->updated();
00384 inc->endUpdates();
00385 } else {
00386 inc->endUpdates();
00387 kWarning() << "Incidence (uid=" << inc->uid()
00388 << ", summary=" << inc->summary()
00389 << ") changed type. Replacing it.";
00390
00391 mResource->calendar()->deleteIncidence( inc );
00392 delete inc;
00393 mResource->calendar()->addIncidence( i->clone() );
00394 }
00395 }
00396 } else {
00397 mResource->calendar()->addIncidence( i->clone() );
00398 }
00399 }
00400 }
00401 return true;
00402 }
00403