1 | /* |
2 | This file is part of the kcal library. |
3 | |
4 | Copyright © 2006 by David Jarvie <software@astrojar.org.uk> |
5 | Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org> |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Library General Public |
9 | License as published by the Free Software Foundation; either |
10 | version 2 of the License, or (at your option) any later version. |
11 | |
12 | This library is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | Library General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU Library General Public License |
18 | along with this library; see the file COPYING.LIB. If not, write to |
19 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | Boston, MA 02110-1301, USA. |
21 | */ |
22 | |
23 | #include "resourcecached.h" |
24 | #include "calendarlocal.h" |
25 | #include "event.h" |
26 | #include "exceptions.h" |
27 | #include "incidence.h" |
28 | #include "journal.h" |
29 | #include "todo.h" |
30 | |
31 | #include "kresources/idmapper.h" |
32 | |
33 | #include <kconfiggroup.h> |
34 | #include <kdebug.h> |
35 | #include <klocalizedstring.h> |
36 | #include <kstandarddirs.h> |
37 | #include <kurl.h> |
38 | |
39 | #include <QtCore/QDateTime> |
40 | #include <QtCore/QDataStream> |
41 | #include <QtCore/QFile> |
42 | #include <QtCore/QString> |
43 | #include <QtCore/QTimer> |
44 | |
45 | |
46 | using namespace KCal; |
47 | |
48 | //@cond PRIVATE |
49 | class ResourceCached::Private |
50 | { |
51 | public: |
52 | Private() |
53 | : mCalendar( QLatin1String( "UTC" ) ), |
54 | mReloadPolicy( ResourceCached::ReloadNever ), |
55 | mReloadInterval( 10 ), |
56 | mInhibitReload( false ), |
57 | mReloaded( false ), |
58 | mSavePending( false ), |
59 | mSavePolicy( ResourceCached::SaveNever ), |
60 | mSaveInterval( 10 ), |
61 | mIdMapper( "kcal/uidmaps/" ) |
62 | {} |
63 | |
64 | CalendarLocal mCalendar; |
65 | |
66 | int mReloadPolicy; |
67 | int mReloadInterval; |
68 | QTimer mReloadTimer; |
69 | bool mInhibitReload; // true to prevent downloads by load(DefaultCache) |
70 | bool mReloaded; // true once it has been downloaded |
71 | bool mSavePending; // true if a save of changes has been scheduled on the timer |
72 | |
73 | int mSavePolicy; |
74 | int mSaveInterval; |
75 | QTimer mSaveTimer; |
76 | |
77 | KDateTime mLastLoad; |
78 | KDateTime mLastSave; |
79 | |
80 | QMap<KCal::Incidence *,bool> mAddedIncidences; |
81 | QMap<KCal::Incidence *,bool> mChangedIncidences; |
82 | QMap<KCal::Incidence *,bool> mDeletedIncidences; |
83 | |
84 | KRES::IdMapper mIdMapper; |
85 | }; |
86 | //@endcond |
87 | |
88 | ResourceCached::ResourceCached() |
89 | : ResourceCalendar(), |
90 | d( new Private ) |
91 | { |
92 | connect( &d->mReloadTimer, SIGNAL(timeout()), SLOT(slotReload()) ); |
93 | connect( &d->mSaveTimer, SIGNAL(timeout()), SLOT(slotSave()) ); |
94 | } |
95 | |
96 | ResourceCached::ResourceCached( const KConfigGroup &group ) |
97 | : ResourceCalendar( group ), |
98 | d( new Private ) |
99 | { |
100 | connect( &d->mReloadTimer, SIGNAL(timeout()), SLOT(slotReload()) ); |
101 | connect( &d->mSaveTimer, SIGNAL(timeout()), SLOT(slotSave()) ); |
102 | } |
103 | |
104 | ResourceCached::~ResourceCached() |
105 | { |
106 | delete d; |
107 | } |
108 | |
109 | CalendarLocal *ResourceCached::calendar() const |
110 | { |
111 | return &d->mCalendar; |
112 | } |
113 | |
114 | bool ResourceCached::defaultReloadInhibited() const |
115 | { |
116 | return d->mInhibitReload; |
117 | } |
118 | |
119 | bool ResourceCached::reloaded() const |
120 | { |
121 | return d->mReloaded; |
122 | } |
123 | |
124 | void ResourceCached::setReloaded( bool done ) |
125 | { |
126 | d->mReloaded = done; |
127 | } |
128 | |
129 | void ResourceCached::setReloadPolicy( int i ) |
130 | { |
131 | d->mReloadPolicy = i; |
132 | |
133 | setupReloadTimer(); |
134 | } |
135 | |
136 | int ResourceCached::reloadPolicy() const |
137 | { |
138 | return d->mReloadPolicy; |
139 | } |
140 | |
141 | void ResourceCached::setReloadInterval( int minutes ) |
142 | { |
143 | d->mReloadInterval = minutes; |
144 | } |
145 | |
146 | int ResourceCached::reloadInterval() const |
147 | { |
148 | return d->mReloadInterval; |
149 | } |
150 | |
151 | bool ResourceCached::inhibitDefaultReload( bool inhibit ) |
152 | { |
153 | if ( inhibit == d->mInhibitReload ) { |
154 | return false; |
155 | } |
156 | d->mInhibitReload = inhibit; |
157 | return true; |
158 | } |
159 | |
160 | void ResourceCached::setSavePolicy( int i ) |
161 | { |
162 | d->mSavePolicy = i; |
163 | |
164 | setupSaveTimer(); |
165 | } |
166 | |
167 | int ResourceCached::savePolicy() const |
168 | { |
169 | return d->mSavePolicy; |
170 | } |
171 | |
172 | void ResourceCached::setSaveInterval( int minutes ) |
173 | { |
174 | d->mSaveInterval = minutes; |
175 | } |
176 | |
177 | int ResourceCached::saveInterval() const |
178 | { |
179 | return d->mSaveInterval; |
180 | } |
181 | |
182 | void ResourceCached::readConfig( const KConfigGroup &group ) |
183 | { |
184 | d->mReloadPolicy = group.readEntry( "ReloadPolicy" , int(ReloadNever) ); |
185 | d->mReloadInterval = group.readEntry( "ReloadInterval" , 10 ); |
186 | |
187 | d->mSaveInterval = group.readEntry( "SaveInterval" , 10 ); |
188 | d->mSavePolicy = group.readEntry( "SavePolicy" , int(SaveNever) ); |
189 | |
190 | QDateTime curDt = QDateTime::currentDateTime(); |
191 | QDateTime dt = group.readEntry( "LastLoad" , curDt ); |
192 | d->mLastLoad = KDateTime( dt, KDateTime::UTC ); |
193 | dt = group.readEntry( "LastSave" , curDt ); |
194 | d->mLastSave = KDateTime( dt, KDateTime::UTC ); |
195 | |
196 | setupSaveTimer(); |
197 | setupReloadTimer(); |
198 | } |
199 | |
200 | void ResourceCached::setupSaveTimer() |
201 | { |
202 | if ( d->mSavePolicy == SaveInterval ) { |
203 | kDebug() << "start save timer (interval " << d->mSaveInterval << "mins)" ; |
204 | d->mSaveTimer.start( d->mSaveInterval * 60 * 1000 ); // n minutes |
205 | } else { |
206 | d->mSaveTimer.stop(); |
207 | } |
208 | } |
209 | |
210 | void ResourceCached::setupReloadTimer() |
211 | { |
212 | if ( d->mReloadPolicy == ReloadInterval ) { |
213 | kDebug() << "start reload timer (interval " << d->mReloadInterval << "mins)" ; |
214 | d->mReloadTimer.start( d->mReloadInterval * 60 * 1000 ); // n minutes |
215 | } else { |
216 | d->mReloadTimer.stop(); |
217 | } |
218 | } |
219 | |
220 | void ResourceCached::writeConfig( KConfigGroup &group ) |
221 | { |
222 | group.writeEntry( "ReloadPolicy" , d->mReloadPolicy ); |
223 | group.writeEntry( "ReloadInterval" , d->mReloadInterval ); |
224 | |
225 | group.writeEntry( "SavePolicy" , d->mSavePolicy ); |
226 | group.writeEntry( "SaveInterval" , d->mSaveInterval ); |
227 | |
228 | group.writeEntry( "LastLoad" , d->mLastLoad.toUtc().dateTime() ); |
229 | group.writeEntry( "LastSave" , d->mLastSave.toUtc().dateTime() ); |
230 | } |
231 | |
232 | bool ResourceCached::addEvent( Event *event ) |
233 | { |
234 | return d->mCalendar.addEvent( event ); |
235 | } |
236 | |
237 | // probably not really efficient, but...it works for now. |
238 | bool ResourceCached::deleteEvent( Event *event ) |
239 | { |
240 | kDebug(); |
241 | |
242 | return d->mCalendar.deleteEvent( event ); |
243 | } |
244 | |
245 | void ResourceCached::deleteAllEvents() |
246 | { |
247 | d->mCalendar.deleteAllEvents(); |
248 | } |
249 | |
250 | Event *ResourceCached::event( const QString &uid ) |
251 | { |
252 | return d->mCalendar.event( uid ); |
253 | } |
254 | |
255 | Event::List ResourceCached::rawEventsForDate( const QDate &qd, const KDateTime::Spec &timeSpec, |
256 | EventSortField sortField, |
257 | SortDirection sortDirection ) |
258 | { |
259 | Event::List list = d->mCalendar.rawEventsForDate( qd, timeSpec, sortField, sortDirection ); |
260 | |
261 | return list; |
262 | } |
263 | |
264 | Event::List ResourceCached::rawEvents( const QDate &start, const QDate &end, |
265 | const KDateTime::Spec &timeSpec, bool inclusive ) |
266 | { |
267 | return d->mCalendar.rawEvents( start, end, timeSpec, inclusive ); |
268 | } |
269 | |
270 | Event::List ResourceCached::rawEventsForDate( const KDateTime &kdt ) |
271 | { |
272 | return d->mCalendar.rawEventsForDate( kdt ); |
273 | } |
274 | |
275 | Event::List ResourceCached::rawEvents( EventSortField sortField, SortDirection sortDirection ) |
276 | { |
277 | return d->mCalendar.rawEvents( sortField, sortDirection ); |
278 | } |
279 | |
280 | bool ResourceCached::addTodo( Todo *todo ) |
281 | { |
282 | return d->mCalendar.addTodo( todo ); |
283 | } |
284 | |
285 | bool ResourceCached::deleteTodo( Todo *todo ) |
286 | { |
287 | return d->mCalendar.deleteTodo( todo ); |
288 | } |
289 | |
290 | void ResourceCached::deleteAllTodos() |
291 | { |
292 | d->mCalendar.deleteAllTodos(); |
293 | } |
294 | |
295 | bool ResourceCached::deleteJournal( Journal *journal ) |
296 | { |
297 | return d->mCalendar.deleteJournal( journal ); |
298 | } |
299 | |
300 | void ResourceCached::deleteAllJournals() |
301 | { |
302 | d->mCalendar.deleteAllJournals(); |
303 | } |
304 | |
305 | Todo::List ResourceCached::rawTodos( TodoSortField sortField, SortDirection sortDirection ) |
306 | { |
307 | return d->mCalendar.rawTodos( sortField, sortDirection ); |
308 | } |
309 | |
310 | Todo *ResourceCached::todo( const QString &uid ) |
311 | { |
312 | return d->mCalendar.todo( uid ); |
313 | } |
314 | |
315 | Todo::List ResourceCached::rawTodosForDate( const QDate &date ) |
316 | { |
317 | return d->mCalendar.rawTodosForDate( date ); |
318 | } |
319 | |
320 | bool ResourceCached::addJournal( Journal *journal ) |
321 | { |
322 | return d->mCalendar.addJournal( journal ); |
323 | } |
324 | |
325 | Journal *ResourceCached::journal( const QString &uid ) |
326 | { |
327 | return d->mCalendar.journal( uid ); |
328 | } |
329 | |
330 | Journal::List ResourceCached::rawJournals( JournalSortField sortField, SortDirection sortDirection ) |
331 | { |
332 | return d->mCalendar.rawJournals( sortField, sortDirection ); |
333 | } |
334 | |
335 | Journal::List ResourceCached::rawJournalsForDate( const QDate &date ) |
336 | { |
337 | return d->mCalendar.rawJournalsForDate( date ); |
338 | } |
339 | |
340 | Alarm::List ResourceCached::alarmsTo( const KDateTime &to ) |
341 | { |
342 | return d->mCalendar.alarmsTo( to ); |
343 | } |
344 | |
345 | Alarm::List ResourceCached::alarms( const KDateTime &from, const KDateTime &to ) |
346 | { |
347 | return d->mCalendar.alarms( from, to ); |
348 | } |
349 | |
350 | void ResourceCached::setTimeSpec( const KDateTime::Spec &timeSpec ) |
351 | { |
352 | d->mCalendar.setTimeSpec( timeSpec ); |
353 | } |
354 | |
355 | KDateTime::Spec ResourceCached::timeSpec() const |
356 | { |
357 | return d->mCalendar.timeSpec(); |
358 | } |
359 | |
360 | void ResourceCached::setTimeZoneId( const QString &tzid ) |
361 | { |
362 | d->mCalendar.setTimeZoneId( tzid ); |
363 | } |
364 | |
365 | QString ResourceCached::timeZoneId() const |
366 | { |
367 | return d->mCalendar.timeZoneId(); |
368 | } |
369 | |
370 | void ResourceCached::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) |
371 | { |
372 | d->mCalendar.shiftTimes( oldSpec, newSpec ); |
373 | } |
374 | |
375 | void ResourceCached::clearChanges() |
376 | { |
377 | d->mAddedIncidences.clear(); |
378 | d->mChangedIncidences.clear(); |
379 | d->mDeletedIncidences.clear(); |
380 | } |
381 | |
382 | bool ResourceCached::load( CacheAction action ) |
383 | { |
384 | kDebug() << resourceName(); |
385 | |
386 | setReceivedLoadError( false ); |
387 | |
388 | bool success = true; |
389 | if ( !isOpen() ) { |
390 | success = open(); //krazy:exclude=syscalls open is a class method |
391 | } |
392 | if ( success ) { |
393 | bool update = false; |
394 | switch ( action ) { |
395 | case DefaultCache: |
396 | if ( !d->mReloaded && !d->mInhibitReload ) { |
397 | update = checkForReload(); |
398 | } |
399 | break; |
400 | case NoSyncCache: |
401 | break; |
402 | case SyncCache: |
403 | update = true; |
404 | break; |
405 | } |
406 | success = doLoad( update ); |
407 | } |
408 | if ( !success && !receivedLoadError() ) { |
409 | loadError(); |
410 | } |
411 | |
412 | // If the resource is read-only, we need to set its incidences to read-only, |
413 | // too. This can't be done at a lower-level, since the read-only setting |
414 | // happens at this level |
415 | if ( !noReadOnlyOnLoad() && readOnly() ) { |
416 | Incidence::List incidences( rawIncidences() ); |
417 | Incidence::List::Iterator it; |
418 | for ( it = incidences.begin(); it != incidences.end(); ++it ) { |
419 | (*it)->setReadOnly( true ); |
420 | } |
421 | } |
422 | |
423 | kDebug() << "Done loading resource" << resourceName(); |
424 | |
425 | if ( success ) { |
426 | emit resourceLoaded( this ); |
427 | } |
428 | |
429 | return success; |
430 | } |
431 | |
432 | bool ResourceCached::load() |
433 | { |
434 | return load( SyncCache ); |
435 | } |
436 | |
437 | bool ResourceCached::loadFromCache() |
438 | { |
439 | setIdMapperIdentifier(); |
440 | d->mIdMapper.load(); |
441 | |
442 | if ( !KStandardDirs::exists( cacheFile() ) ) { |
443 | return false; |
444 | } |
445 | d->mCalendar.load( cacheFile() ); |
446 | if ( !noReadOnlyOnLoad() && readOnly() ) { |
447 | Incidence::List incidences( rawIncidences() ); |
448 | Incidence::List::Iterator it; |
449 | for ( it = incidences.begin(); it != incidences.end(); ++it ) { |
450 | (*it)->setReadOnly( true ); |
451 | } |
452 | } |
453 | return true; |
454 | } |
455 | |
456 | bool ResourceCached::save( CacheAction action, Incidence *incidence ) |
457 | { |
458 | if ( !incidence && ( d->mSavePolicy == SaveAlways || d->mSavePolicy == SaveDelayed ) ) { |
459 | d->mSaveTimer.stop(); // in case it's called manually while save is pending |
460 | } |
461 | d->mSavePending = false; |
462 | if ( saveInhibited() ) { |
463 | return true; |
464 | } |
465 | if ( !readOnly() ) { |
466 | kDebug() << "Save resource" << resourceName(); |
467 | |
468 | setReceivedSaveError( false ); |
469 | |
470 | if ( !isOpen() ) { |
471 | return true; |
472 | } |
473 | bool upload = false; |
474 | switch ( action ) { |
475 | case DefaultCache: |
476 | upload = checkForSave(); |
477 | break; |
478 | case NoSyncCache: |
479 | break; |
480 | case SyncCache: |
481 | upload = true; |
482 | break; |
483 | } |
484 | bool success = incidence ? doSave( upload, incidence ) : doSave( upload ); |
485 | if ( !success && !receivedSaveError() ) { |
486 | saveError(); |
487 | } else { |
488 | emit resourceSaved( this ); |
489 | } |
490 | return success; |
491 | } else { |
492 | // Read-only, just don't save... |
493 | kDebug() << "Don't save read-only resource" << resourceName(); |
494 | return true; |
495 | } |
496 | } |
497 | |
498 | bool ResourceCached::save( Incidence *incidence ) |
499 | { |
500 | return save( SyncCache, incidence ); |
501 | } |
502 | |
503 | bool ResourceCached::doSave( bool syncCache, Incidence *incidence ) |
504 | { |
505 | Q_UNUSED( incidence ); |
506 | return doSave( syncCache ); |
507 | } |
508 | |
509 | void ResourceCached::saveToCache() |
510 | { |
511 | kDebug() << cacheFile(); |
512 | |
513 | setIdMapperIdentifier(); |
514 | d->mIdMapper.save(); |
515 | |
516 | d->mCalendar.save( cacheFile() ); |
517 | } |
518 | |
519 | void ResourceCached::setIdMapperIdentifier() |
520 | { |
521 | d->mIdMapper.setIdentifier( type() + '_' + identifier() ); |
522 | } |
523 | |
524 | void ResourceCached::clearCache() |
525 | { |
526 | d->mCalendar.close(); |
527 | } |
528 | |
529 | void ResourceCached::cleanUpEventCache( const Event::List &eventList ) |
530 | { |
531 | CalendarLocal calendar ( QLatin1String( "UTC" ) ); |
532 | |
533 | if ( KStandardDirs::exists( cacheFile() ) ) { |
534 | calendar.load( cacheFile() ); |
535 | } else { |
536 | return; |
537 | } |
538 | |
539 | Event::List list = calendar.events(); |
540 | Event::List::ConstIterator cacheIt, it; |
541 | for ( cacheIt = list.constBegin(); cacheIt != list.constEnd(); ++cacheIt ) { |
542 | bool found = false; |
543 | for ( it = eventList.begin(); it != eventList.end(); ++it ) { |
544 | if ( (*it)->uid() == (*cacheIt)->uid() ) { |
545 | found = true; |
546 | break; |
547 | } |
548 | } |
549 | |
550 | if ( !found ) { |
551 | d->mIdMapper.removeRemoteId( d->mIdMapper.remoteId( (*cacheIt)->uid() ) ); |
552 | Event *event = d->mCalendar.event( (*cacheIt)->uid() ); |
553 | if ( event ) { |
554 | d->mCalendar.deleteEvent( event ); |
555 | } |
556 | } |
557 | } |
558 | |
559 | calendar.close(); |
560 | } |
561 | |
562 | void ResourceCached::cleanUpTodoCache( const Todo::List &todoList ) |
563 | { |
564 | CalendarLocal calendar ( QLatin1String( "UTC" ) ); |
565 | |
566 | if ( KStandardDirs::exists( cacheFile() ) ) { |
567 | calendar.load( cacheFile() ); |
568 | } else { |
569 | return; |
570 | } |
571 | |
572 | Todo::List list = calendar.todos(); |
573 | Todo::List::ConstIterator cacheIt, it; |
574 | for ( cacheIt = list.constBegin(); cacheIt != list.constEnd(); ++cacheIt ) { |
575 | |
576 | bool found = false; |
577 | for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) { |
578 | if ( (*it)->uid() == (*cacheIt)->uid() ) { |
579 | found = true; |
580 | } |
581 | } |
582 | |
583 | if ( !found ) { |
584 | d->mIdMapper.removeRemoteId( d->mIdMapper.remoteId( (*cacheIt)->uid() ) ); |
585 | Todo *todo = d->mCalendar.todo( (*cacheIt)->uid() ); |
586 | if ( todo ) { |
587 | d->mCalendar.deleteTodo( todo ); |
588 | } |
589 | } |
590 | } |
591 | |
592 | calendar.close(); |
593 | } |
594 | |
595 | KRES::IdMapper &ResourceCached::idMapper() |
596 | { |
597 | return d->mIdMapper; |
598 | } |
599 | |
600 | QString ResourceCached::cacheFile() const |
601 | { |
602 | return KStandardDirs::locateLocal( "cache" , "kcal/kresources/" + identifier() ); |
603 | } |
604 | |
605 | QString ResourceCached::changesCacheFile( const QString &type ) const |
606 | { |
607 | return KStandardDirs::locateLocal( "cache" , "kcal/changescache/" + identifier() + '_' + type ); |
608 | } |
609 | |
610 | void ResourceCached::saveChangesCache( const QMap<Incidence *, bool> &map, const QString &type ) |
611 | { |
612 | CalendarLocal calendar ( QLatin1String( "UTC" ) ); |
613 | |
614 | bool isEmpty = true; |
615 | QMap<Incidence *,bool>::ConstIterator it; |
616 | for ( it = map.begin(); it != map.end(); ++it ) { |
617 | isEmpty = false; |
618 | calendar.addIncidence( it.key()->clone() ); |
619 | } |
620 | |
621 | if ( !isEmpty ) { |
622 | calendar.save( changesCacheFile( type ) ); |
623 | } else { |
624 | QFile file( changesCacheFile( type ) ); |
625 | file.remove(); |
626 | } |
627 | |
628 | calendar.close(); |
629 | } |
630 | |
631 | void ResourceCached::saveChangesCache() |
632 | { |
633 | saveChangesCache( d->mAddedIncidences, "added" ); |
634 | saveChangesCache( d->mDeletedIncidences, "deleted" ); |
635 | saveChangesCache( d->mChangedIncidences, "changed" ); |
636 | } |
637 | |
638 | void ResourceCached::loadChangesCache( QMap<Incidence *, bool> &map, const QString &type ) |
639 | { |
640 | CalendarLocal calendar ( QLatin1String( "UTC" ) ); |
641 | |
642 | if ( KStandardDirs::exists( changesCacheFile( type ) ) ) { |
643 | calendar.load( changesCacheFile( type ) ); |
644 | } else { |
645 | return; |
646 | } |
647 | |
648 | const Incidence::List list = calendar.incidences(); |
649 | Incidence::List::ConstIterator it; |
650 | for ( it = list.begin(); it != list.end(); ++it ) { |
651 | map.insert( (*it)->clone(), true ); |
652 | } |
653 | |
654 | calendar.close(); |
655 | } |
656 | |
657 | void ResourceCached::loadChangesCache() |
658 | { |
659 | loadChangesCache( d->mAddedIncidences, "added" ); |
660 | loadChangesCache( d->mDeletedIncidences, "deleted" ); |
661 | loadChangesCache( d->mChangedIncidences, "changed" ); |
662 | } |
663 | |
664 | void ResourceCached::calendarIncidenceAdded( Incidence *i ) |
665 | { |
666 | kDebug() << i->uid(); |
667 | |
668 | QMap<Incidence *,bool>::ConstIterator it; |
669 | it = d->mAddedIncidences.constFind( i ); |
670 | if ( it == d->mAddedIncidences.constEnd() ) { |
671 | d->mAddedIncidences.insert( i, true ); |
672 | } |
673 | |
674 | checkForAutomaticSave(); |
675 | } |
676 | |
677 | void ResourceCached::calendarIncidenceChanged( Incidence *i ) |
678 | { |
679 | kDebug() << i->uid(); |
680 | |
681 | QMap<Incidence *,bool>::ConstIterator it; |
682 | it = d->mChangedIncidences.constFind( i ); |
683 | // FIXME: If you modify an added incidence, there's no need to add it to d->mChangedIncidences! |
684 | if ( it == d->mChangedIncidences.constEnd() ) { |
685 | d->mChangedIncidences.insert( i, true ); |
686 | } |
687 | |
688 | checkForAutomaticSave(); |
689 | } |
690 | |
691 | void ResourceCached::calendarIncidenceDeleted( Incidence *i ) |
692 | { |
693 | kDebug() << i->uid(); |
694 | |
695 | QMap<Incidence *,bool>::ConstIterator it; |
696 | it = d->mDeletedIncidences.constFind( i ); |
697 | if ( it == d->mDeletedIncidences.constEnd() ) { |
698 | d->mDeletedIncidences.insert( i, true ); |
699 | } |
700 | |
701 | checkForAutomaticSave(); |
702 | } |
703 | |
704 | Incidence::List ResourceCached::addedIncidences() const |
705 | { |
706 | Incidence::List added; |
707 | QMap<Incidence *,bool>::ConstIterator it; |
708 | for ( it = d->mAddedIncidences.constBegin(); it != d->mAddedIncidences.constEnd(); ++it ) { |
709 | added.append( it.key() ); |
710 | } |
711 | return added; |
712 | } |
713 | |
714 | Incidence::List ResourceCached::changedIncidences() const |
715 | { |
716 | Incidence::List changed; |
717 | QMap<Incidence *,bool>::ConstIterator it; |
718 | for ( it = d->mChangedIncidences.constBegin(); it != d->mChangedIncidences.constEnd(); ++it ) { |
719 | changed.append( it.key() ); |
720 | } |
721 | return changed; |
722 | } |
723 | |
724 | Incidence::List ResourceCached::deletedIncidences() const |
725 | { |
726 | Incidence::List deleted; |
727 | QMap<Incidence *,bool>::ConstIterator it; |
728 | for ( it = d->mDeletedIncidences.constBegin(); it != d->mDeletedIncidences.constEnd(); ++it ) { |
729 | deleted.append( it.key() ); |
730 | } |
731 | return deleted; |
732 | } |
733 | |
734 | Incidence::List ResourceCached::allChanges() const |
735 | { |
736 | Incidence::List changes; |
737 | QMap<Incidence *,bool>::ConstIterator it; |
738 | for ( it = d->mAddedIncidences.constBegin(); it != d->mAddedIncidences.constEnd(); ++it ) { |
739 | changes.append( it.key() ); |
740 | } |
741 | for ( it = d->mChangedIncidences.constBegin(); it != d->mChangedIncidences.constEnd(); ++it ) { |
742 | changes.append( it.key() ); |
743 | } |
744 | for ( it = d->mDeletedIncidences.constBegin(); it != d->mDeletedIncidences.constEnd(); ++it ) { |
745 | changes.append( it.key() ); |
746 | } |
747 | return changes; |
748 | } |
749 | |
750 | bool ResourceCached::hasChanges() const |
751 | { |
752 | return !( d->mAddedIncidences.isEmpty() && d->mChangedIncidences.isEmpty() && |
753 | d->mDeletedIncidences.isEmpty() ); |
754 | } |
755 | |
756 | void ResourceCached::clearChange( Incidence *incidence ) |
757 | { |
758 | clearChange( incidence->uid() ); |
759 | } |
760 | |
761 | void ResourceCached::clearChange( const QString &uid ) |
762 | { |
763 | QMap<Incidence *, bool>::Iterator it; |
764 | |
765 | for ( it = d->mAddedIncidences.begin(); it != d->mAddedIncidences.end(); ++it ) { |
766 | if ( it.key()->uid() == uid ) { |
767 | d->mAddedIncidences.erase( it ); |
768 | break; |
769 | } |
770 | } |
771 | |
772 | for ( it = d->mChangedIncidences.begin(); it != d->mChangedIncidences.end(); ++it ) { |
773 | if ( it.key()->uid() == uid ) { |
774 | d->mChangedIncidences.erase( it ); |
775 | break; |
776 | } |
777 | } |
778 | |
779 | for ( it = d->mDeletedIncidences.begin(); it != d->mDeletedIncidences.end(); ++it ) { |
780 | if ( it.key()->uid() == uid ) { |
781 | d->mDeletedIncidences.erase( it ); |
782 | break; |
783 | } |
784 | } |
785 | } |
786 | |
787 | void ResourceCached::enableChangeNotification() |
788 | { |
789 | d->mCalendar.registerObserver( this ); |
790 | } |
791 | |
792 | void ResourceCached::disableChangeNotification() |
793 | { |
794 | d->mCalendar.unregisterObserver( this ); |
795 | } |
796 | |
797 | void ResourceCached::slotReload() |
798 | { |
799 | if ( !isActive() ) { |
800 | return; |
801 | } |
802 | |
803 | kDebug(); |
804 | |
805 | load( SyncCache ); |
806 | } |
807 | |
808 | void ResourceCached::slotSave() |
809 | { |
810 | if ( !isActive() ) { |
811 | return; |
812 | } |
813 | |
814 | kDebug(); |
815 | |
816 | save( SyncCache ); |
817 | } |
818 | |
819 | void ResourceCached::checkForAutomaticSave() |
820 | { |
821 | if ( d->mSavePolicy == SaveAlways ) { |
822 | kDebug() << "save now" ; |
823 | d->mSavePending = true; |
824 | d->mSaveTimer.setSingleShot( true ); |
825 | d->mSaveTimer.start( 1 * 1000 ); // 1 second |
826 | } else if ( d->mSavePolicy == SaveDelayed ) { |
827 | kDebug() << "save delayed" ; |
828 | d->mSavePending = true; |
829 | d->mSaveTimer.setSingleShot( true ); |
830 | d->mSaveTimer.start( 15 * 1000 ); // 15 seconds |
831 | } |
832 | } |
833 | |
834 | bool ResourceCached::checkForReload() |
835 | { |
836 | if ( d->mReloadPolicy == ReloadNever ) { |
837 | return false; |
838 | } |
839 | if ( d->mReloadPolicy == ReloadOnStartup ) { |
840 | return !d->mReloaded; |
841 | } |
842 | return true; |
843 | } |
844 | |
845 | bool ResourceCached::checkForSave() |
846 | { |
847 | if ( d->mSavePolicy == SaveNever ) { |
848 | return false; |
849 | } |
850 | return true; |
851 | } |
852 | |
853 | void ResourceCached::addInfoText( QString &txt ) const |
854 | { |
855 | if ( d->mLastLoad.isValid() ) { |
856 | txt += "<br>" ; |
857 | txt += i18n( "Last loaded: %1" , |
858 | KGlobal::locale()->formatDateTime( d->mLastLoad.toUtc().dateTime() ) ); |
859 | } |
860 | if ( d->mLastSave.isValid() ) { |
861 | txt += "<br>" ; |
862 | txt += i18n( "Last saved: %1" , |
863 | KGlobal::locale()->formatDateTime( d->mLastSave.toUtc().dateTime() ) ); |
864 | } |
865 | } |
866 | |
867 | void ResourceCached::doClose() |
868 | { |
869 | if ( d->mSavePending ) { |
870 | d->mSaveTimer.stop(); |
871 | } |
872 | if ( d->mSavePending || d->mSavePolicy == SaveOnExit || d->mSavePolicy == SaveInterval ) { |
873 | save( SyncCache ); |
874 | } |
875 | d->mCalendar.close(); |
876 | } |
877 | |
878 | bool ResourceCached::doOpen() |
879 | { |
880 | kDebug() << "Opening resource" << resourceName(); |
881 | return true; |
882 | } |
883 | |
884 | void KCal::ResourceCached::setOwner( const Person &owner ) |
885 | { |
886 | d->mCalendar.setOwner( owner ); |
887 | } |
888 | |
889 | Person KCal::ResourceCached::owner() const |
890 | { |
891 | return d->mCalendar.owner(); |
892 | } |
893 | |