1 | /* |
2 | This file is part of the kcal library. |
3 | |
4 | Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> |
5 | Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> |
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 | @file |
24 | This file is part of the API for handling calendar data and |
25 | defines the CalendarResources class. |
26 | |
27 | @brief |
28 | This class provides a Calendar which is composed of other Calendars |
29 | known as "Resources". |
30 | |
31 | @author Cornelius Schumacher \<schumacher@kde.org\> |
32 | @author Reinhold Kainhofer \<reinhold@kainhofer.com\> |
33 | */ |
34 | |
35 | #include "calendarresources.h" |
36 | #include "incidence.h" |
37 | #include "journal.h" |
38 | #include "resourcecalendar.h" |
39 | |
40 | #include "kresources/manager.h" |
41 | #include "kresources/selectdialog.h" |
42 | #include "kabc/lock.h" |
43 | |
44 | #include <kdebug.h> |
45 | #include <kdatetime.h> |
46 | #include <kstandarddirs.h> |
47 | #include <klocalizedstring.h> |
48 | |
49 | #include <QtCore/QString> |
50 | #include <QtCore/QList> |
51 | |
52 | #include <stdlib.h> |
53 | |
54 | using namespace KCal; |
55 | |
56 | /** |
57 | Private classes that helps to provide binary compatibility between releases. |
58 | @internal |
59 | */ |
60 | //@cond PRIVATE |
61 | class KCal::CalendarResources::Private |
62 | { |
63 | public: |
64 | Private( const QString &family ) |
65 | : mAddingInProgress( false ), |
66 | mLastUsedResource( 0 ), |
67 | mManager( new CalendarResourceManager( family ) ), |
68 | mStandardPolicy( new StandardDestinationPolicy( mManager ) ), |
69 | mDestinationPolicy( mStandardPolicy ), |
70 | mAskPolicy( new AskDestinationPolicy( mManager ) ), |
71 | mException( 0 ), |
72 | mPendingDeleteFromResourceMap( false ) |
73 | {} |
74 | ~Private() |
75 | { |
76 | delete mManager; |
77 | delete mStandardPolicy; |
78 | delete mAskPolicy; |
79 | } |
80 | bool mAddingInProgress; |
81 | ResourceCalendar *mLastUsedResource; |
82 | |
83 | bool mOpen; //flag that indicates if the resources are "open" |
84 | |
85 | KRES::Manager<ResourceCalendar>* mManager; |
86 | QMap <Incidence*, ResourceCalendar*> mResourceMap; |
87 | |
88 | StandardDestinationPolicy *mStandardPolicy; |
89 | DestinationPolicy *mDestinationPolicy; |
90 | AskDestinationPolicy *mAskPolicy; |
91 | |
92 | QMap<ResourceCalendar *, Ticket *> mTickets; |
93 | QMap<ResourceCalendar *, int> mChangeCounts; |
94 | |
95 | ErrorFormat *mException; |
96 | |
97 | bool mPendingDeleteFromResourceMap; |
98 | |
99 | template< class IncidenceList > |
100 | void appendIncidences( IncidenceList &result, const IncidenceList &, |
101 | ResourceCalendar * ); |
102 | }; |
103 | |
104 | class KCal::CalendarResources::DestinationPolicy::Private |
105 | { |
106 | public: |
107 | Private( CalendarResourceManager *manager, QWidget *parent ) |
108 | : mManager( manager ), |
109 | mParent( parent ) |
110 | {} |
111 | CalendarResourceManager *mManager; |
112 | QWidget *mParent; |
113 | }; |
114 | |
115 | class KCal::CalendarResources::StandardDestinationPolicy::Private |
116 | { |
117 | public: |
118 | Private() |
119 | {} |
120 | }; |
121 | |
122 | class KCal::CalendarResources::AskDestinationPolicy::Private |
123 | { |
124 | public: |
125 | Private() |
126 | {} |
127 | }; |
128 | |
129 | class KCal::CalendarResources::Ticket::Private |
130 | { |
131 | public: |
132 | Private( ResourceCalendar *resource ) |
133 | : mResource( resource ) |
134 | {} |
135 | ResourceCalendar *mResource; |
136 | }; |
137 | //@endcond |
138 | |
139 | CalendarResources::DestinationPolicy::DestinationPolicy( |
140 | CalendarResourceManager *manager, QWidget *parent ) |
141 | : d( new KCal::CalendarResources::DestinationPolicy::Private( manager, parent ) ) |
142 | { |
143 | } |
144 | |
145 | CalendarResources::DestinationPolicy::~DestinationPolicy() |
146 | { |
147 | delete d; |
148 | } |
149 | |
150 | QWidget *CalendarResources::DestinationPolicy::parent() |
151 | { |
152 | return d->mParent; |
153 | } |
154 | |
155 | void CalendarResources::DestinationPolicy::setParent( QWidget *parent ) |
156 | { |
157 | d->mParent = parent; |
158 | } |
159 | |
160 | CalendarResourceManager *CalendarResources::DestinationPolicy::resourceManager() |
161 | { |
162 | return d->mManager; |
163 | } |
164 | |
165 | bool CalendarResources::DestinationPolicy::hasCalendarResources() |
166 | { |
167 | CalendarResourceManager::ActiveIterator it; |
168 | for ( it = resourceManager()->activeBegin(); |
169 | it != resourceManager()->activeEnd(); ++it ) { |
170 | if ( !(*it)->readOnly() ) { |
171 | if ( resourceManager()->standardResource() == *it ) { |
172 | return true; |
173 | } else { |
174 | return true; |
175 | } |
176 | } |
177 | } |
178 | return false; |
179 | } |
180 | |
181 | CalendarResources::StandardDestinationPolicy::StandardDestinationPolicy( |
182 | CalendarResourceManager *manager, QWidget *parent ) |
183 | : DestinationPolicy( manager, parent ), |
184 | d( new KCal::CalendarResources::StandardDestinationPolicy::Private ) |
185 | { |
186 | } |
187 | |
188 | CalendarResources::StandardDestinationPolicy::~StandardDestinationPolicy() |
189 | { |
190 | delete d; |
191 | } |
192 | |
193 | ResourceCalendar *CalendarResources::StandardDestinationPolicy::destination( Incidence *incidence ) |
194 | { |
195 | Q_UNUSED( incidence ); |
196 | return resourceManager()->standardResource(); |
197 | } |
198 | |
199 | CalendarResources::AskDestinationPolicy::AskDestinationPolicy( |
200 | CalendarResourceManager *manager, QWidget *parent ) |
201 | : DestinationPolicy( manager, parent ), |
202 | d( new KCal::CalendarResources::AskDestinationPolicy::Private ) |
203 | { |
204 | } |
205 | |
206 | CalendarResources::AskDestinationPolicy::~AskDestinationPolicy() |
207 | { |
208 | delete d; |
209 | } |
210 | |
211 | ResourceCalendar *CalendarResources::AskDestinationPolicy::destination( Incidence *incidence ) |
212 | { |
213 | Q_UNUSED( incidence ); |
214 | QList<KRES::Resource*> list; |
215 | |
216 | CalendarResourceManager::ActiveIterator it; |
217 | for ( it = resourceManager()->activeBegin(); |
218 | it != resourceManager()->activeEnd(); ++it ) { |
219 | if ( !(*it)->readOnly() ) { |
220 | //Insert the first the Standard resource to get be the default selected. |
221 | if ( resourceManager()->standardResource() == *it ) { |
222 | list.insert( 0, *it ); |
223 | } else { |
224 | list.append( *it ); |
225 | } |
226 | } |
227 | } |
228 | |
229 | KRES::Resource *r; |
230 | r = KRES::SelectDialog::getResource( list, parent() ); |
231 | return static_cast<ResourceCalendar *>( r ); |
232 | } |
233 | |
234 | CalendarResources::CalendarResources( const KDateTime::Spec &timeSpec, |
235 | const QString &family ) |
236 | : Calendar( timeSpec ), |
237 | d( new KCal::CalendarResources::Private( family ) ) |
238 | { |
239 | |
240 | connect( this, SIGNAL(batchAddingBegins()), this, SLOT(beginAddingIncidences()) ); |
241 | connect( this, SIGNAL(batchAddingEnds()), this, SLOT(endAddingIncidences()) ); |
242 | |
243 | d->mManager->addObserver( this ); |
244 | } |
245 | |
246 | CalendarResources::CalendarResources( const QString &timeZoneId, |
247 | const QString &family ) |
248 | : Calendar( timeZoneId ), |
249 | d( new KCal::CalendarResources::Private( family ) ) |
250 | { |
251 | connect( this, SIGNAL(batchAddingBegins()), this, SLOT(beginAddingIncidences()) ); |
252 | connect( this, SIGNAL(batchAddingEnds()), this, SLOT(endAddingIncidences()) ); |
253 | |
254 | d->mManager->addObserver( this ); |
255 | } |
256 | |
257 | CalendarResources::~CalendarResources() |
258 | { |
259 | close(); |
260 | clearException(); |
261 | delete d; |
262 | } |
263 | |
264 | void CalendarResources::clearException() |
265 | { |
266 | delete d->mException; |
267 | d->mException = 0; |
268 | } |
269 | |
270 | ErrorFormat *CalendarResources::exception() |
271 | { |
272 | return d->mException; |
273 | } |
274 | |
275 | void CalendarResources::readConfig( KConfig *config ) |
276 | { |
277 | d->mManager->readConfig( config ); |
278 | |
279 | CalendarResourceManager::Iterator it; |
280 | for ( it = d->mManager->begin(); it != d->mManager->end(); ++it ) { |
281 | connectResource( *it ); |
282 | } |
283 | } |
284 | |
285 | void CalendarResources::load() |
286 | { |
287 | if ( !d->mManager->standardResource() ) { |
288 | kDebug() << "Warning! No standard resource yet." ; |
289 | } |
290 | |
291 | // set the timezone for all resources. Otherwise we'll have those terrible tz |
292 | // troubles ;-(( |
293 | CalendarResourceManager::Iterator i1; |
294 | for ( i1 = d->mManager->begin(); i1 != d->mManager->end(); ++i1 ) { |
295 | (*i1)->setTimeSpec( timeSpec() ); |
296 | } |
297 | |
298 | QList<ResourceCalendar *> failed; |
299 | |
300 | // Open all active resources |
301 | CalendarResourceManager::ActiveIterator it; |
302 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
303 | if ( !(*it)->load() ) { |
304 | failed.append( *it ); |
305 | } |
306 | Incidence::List incidences = (*it)->rawIncidences(); |
307 | Incidence::List::Iterator incit; |
308 | for ( incit = incidences.begin(); incit != incidences.end(); ++incit ) { |
309 | (*incit)->registerObserver( this ); |
310 | notifyIncidenceAdded( *incit ); |
311 | } |
312 | } |
313 | |
314 | QList<ResourceCalendar *>::ConstIterator it2; |
315 | for ( it2 = failed.constBegin(); it2 != failed.constEnd(); ++it2 ) { |
316 | (*it2)->setActive( false ); |
317 | emit signalResourceModified( *it2 ); |
318 | } |
319 | |
320 | d->mOpen = true; |
321 | emit calendarLoaded(); |
322 | } |
323 | |
324 | bool CalendarResources::reload() |
325 | { |
326 | save(); |
327 | close(); |
328 | load(); |
329 | return true; |
330 | } |
331 | |
332 | CalendarResourceManager *CalendarResources::resourceManager() const |
333 | { |
334 | return d->mManager; |
335 | } |
336 | |
337 | void CalendarResources::setStandardDestinationPolicy() |
338 | { |
339 | d->mDestinationPolicy = d->mStandardPolicy; |
340 | } |
341 | |
342 | void CalendarResources::setAskDestinationPolicy() |
343 | { |
344 | d->mDestinationPolicy = d->mAskPolicy; |
345 | } |
346 | |
347 | QWidget *CalendarResources::dialogParentWidget() |
348 | { |
349 | return d->mDestinationPolicy->parent(); |
350 | } |
351 | |
352 | void CalendarResources::setDialogParentWidget( QWidget *parent ) |
353 | { |
354 | d->mDestinationPolicy->setParent( parent ); |
355 | } |
356 | |
357 | void CalendarResources::close() |
358 | { |
359 | if ( d->mOpen ) { |
360 | CalendarResourceManager::ActiveIterator it; |
361 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
362 | (*it)->close(); |
363 | } |
364 | |
365 | setModified( false ); |
366 | d->mOpen = false; |
367 | } |
368 | } |
369 | |
370 | bool CalendarResources::save() |
371 | { |
372 | bool status = true; |
373 | if ( d->mOpen && isModified() ) { |
374 | status = false; |
375 | CalendarResourceManager::ActiveIterator it; |
376 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
377 | status = (*it)->save() || status; |
378 | } |
379 | setModified( false ); |
380 | } |
381 | |
382 | return status; |
383 | } |
384 | |
385 | bool CalendarResources::isSaving() |
386 | { |
387 | CalendarResourceManager::ActiveIterator it; |
388 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
389 | if ( (*it)->isSaving() ) { |
390 | return true; |
391 | } |
392 | } |
393 | return false; |
394 | } |
395 | |
396 | bool CalendarResources::addIncidence( Incidence *incidence, |
397 | ResourceCalendar *resource ) |
398 | { |
399 | // FIXME: Use proper locking via begin/endChange! |
400 | bool validRes = false; |
401 | CalendarResourceManager::ActiveIterator it; |
402 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
403 | if ( (*it) == resource ) { |
404 | validRes = true; |
405 | } |
406 | } |
407 | |
408 | ResourceCalendar *oldResource = 0; |
409 | if ( d->mResourceMap.contains( incidence ) ) { |
410 | oldResource = d->mResourceMap[incidence]; |
411 | } |
412 | d->mResourceMap[incidence] = resource; |
413 | if ( validRes && beginChange( incidence ) && |
414 | resource->addIncidence( incidence ) ) { |
415 | // d->mResourceMap[incidence] = resource; |
416 | incidence->registerObserver( this ); |
417 | notifyIncidenceAdded( incidence ); |
418 | setModified( true ); |
419 | endChange( incidence ); |
420 | return true; |
421 | } else { |
422 | if ( oldResource ) { |
423 | d->mResourceMap[incidence] = oldResource; |
424 | } else { |
425 | d->mResourceMap.remove( incidence ); |
426 | } |
427 | } |
428 | |
429 | return false; |
430 | } |
431 | |
432 | bool CalendarResources::addIncidence( Incidence *incidence ) |
433 | { |
434 | clearException(); |
435 | |
436 | ResourceCalendar *resource = d->mLastUsedResource; |
437 | |
438 | if ( !d->mAddingInProgress || d->mLastUsedResource == 0 ) { |
439 | resource = d->mDestinationPolicy->destination( incidence ); |
440 | d->mLastUsedResource = resource; |
441 | } |
442 | |
443 | if ( resource ) { |
444 | d->mResourceMap[ incidence ] = resource; |
445 | |
446 | if ( beginChange( incidence ) && resource->addIncidence( incidence ) ) { |
447 | incidence->registerObserver( this ); |
448 | notifyIncidenceAdded( incidence ); |
449 | |
450 | d->mResourceMap[ incidence ] = resource; |
451 | setModified( true ); |
452 | endChange( incidence ); |
453 | return true; |
454 | } else { |
455 | d->mResourceMap.remove( incidence ); |
456 | } |
457 | } else { |
458 | d->mException = new ErrorFormat( ErrorFormat::UserCancel ); |
459 | } |
460 | |
461 | return false; |
462 | } |
463 | |
464 | bool CalendarResources::addEvent( Event *event ) |
465 | { |
466 | return addIncidence( event ); |
467 | } |
468 | |
469 | bool CalendarResources::addEvent( Event *Event, ResourceCalendar *resource ) |
470 | { |
471 | return addIncidence( Event, resource ); |
472 | } |
473 | |
474 | bool CalendarResources::deleteEvent( Event *event ) |
475 | { |
476 | bool status; |
477 | if ( d->mResourceMap.find( event ) != d->mResourceMap.end() ) { |
478 | status = d->mResourceMap[event]->deleteEvent( event ); |
479 | if ( status ) { |
480 | d->mPendingDeleteFromResourceMap = true; |
481 | } |
482 | } else { |
483 | status = false; |
484 | CalendarResourceManager::ActiveIterator it; |
485 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
486 | status = (*it)->deleteEvent( event ) || status; |
487 | } |
488 | } |
489 | if ( status ) { |
490 | notifyIncidenceDeleted( event ); |
491 | } |
492 | |
493 | setModified( status ); |
494 | return status; |
495 | } |
496 | |
497 | void CalendarResources::deleteAllEvents() |
498 | { |
499 | CalendarResourceManager::ActiveIterator it; |
500 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
501 | (*it)->deleteAllEvents(); |
502 | } |
503 | } |
504 | |
505 | Event *CalendarResources::event( const QString &uid ) |
506 | { |
507 | CalendarResourceManager::ActiveIterator it; |
508 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
509 | Event *event = (*it)->event( uid ); |
510 | if ( event ) { |
511 | d->mResourceMap[event] = *it; |
512 | return event; |
513 | } |
514 | } |
515 | |
516 | // Not found |
517 | return 0; |
518 | } |
519 | |
520 | bool CalendarResources::addTodo( Todo *todo ) |
521 | { |
522 | return addIncidence( todo ); |
523 | } |
524 | |
525 | bool CalendarResources::addTodo( Todo *todo, ResourceCalendar *resource ) |
526 | { |
527 | return addIncidence( todo, resource ); |
528 | } |
529 | |
530 | bool CalendarResources::deleteTodo( Todo *todo ) |
531 | { |
532 | bool status; |
533 | if ( d->mResourceMap.find( todo ) != d->mResourceMap.end() ) { |
534 | status = d->mResourceMap[todo]->deleteTodo( todo ); |
535 | if ( status ) { |
536 | d->mPendingDeleteFromResourceMap = true; |
537 | } |
538 | } else { |
539 | CalendarResourceManager::ActiveIterator it; |
540 | status = false; |
541 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
542 | status = (*it)->deleteTodo( todo ) || status; |
543 | } |
544 | } |
545 | |
546 | setModified( status ); |
547 | return status; |
548 | } |
549 | |
550 | void CalendarResources::deleteAllTodos() |
551 | { |
552 | CalendarResourceManager::ActiveIterator it; |
553 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
554 | (*it)->deleteAllTodos(); |
555 | } |
556 | } |
557 | |
558 | Todo::List CalendarResources::rawTodos( TodoSortField sortField, |
559 | SortDirection sortDirection ) |
560 | { |
561 | Todo::List result; |
562 | |
563 | CalendarResourceManager::ActiveIterator it; |
564 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
565 | d->appendIncidences<Todo::List>( result, |
566 | (*it)->rawTodos( TodoSortUnsorted ), *it ); |
567 | } |
568 | return sortTodos( &result, sortField, sortDirection ); |
569 | } |
570 | |
571 | Todo *CalendarResources::todo( const QString &uid ) |
572 | { |
573 | CalendarResourceManager::ActiveIterator it; |
574 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
575 | Todo *todo = (*it)->todo( uid ); |
576 | if ( todo ) { |
577 | d->mResourceMap[todo] = *it; |
578 | return todo; |
579 | } |
580 | } |
581 | |
582 | // Not found |
583 | return 0; |
584 | } |
585 | |
586 | Todo::List CalendarResources::rawTodosForDate( const QDate &date ) |
587 | { |
588 | Todo::List result; |
589 | |
590 | CalendarResourceManager::ActiveIterator it; |
591 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
592 | d->appendIncidences<Todo::List>( result, |
593 | (*it)->rawTodosForDate( date ), *it ); |
594 | } |
595 | return result; |
596 | } |
597 | |
598 | Alarm::List CalendarResources::alarmsTo( const KDateTime &to ) |
599 | { |
600 | Alarm::List result; |
601 | CalendarResourceManager::ActiveIterator it; |
602 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
603 | result += (*it)->alarmsTo( to ); |
604 | } |
605 | return result; |
606 | } |
607 | |
608 | Alarm::List CalendarResources::alarms( const KDateTime &from, |
609 | const KDateTime &to ) |
610 | { |
611 | Alarm::List result; |
612 | CalendarResourceManager::ActiveIterator it; |
613 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
614 | result += (*it)->alarms( from, to ); |
615 | } |
616 | return result; |
617 | } |
618 | |
619 | bool CalendarResources::hasCalendarResources() |
620 | { |
621 | return d->mDestinationPolicy->hasCalendarResources(); |
622 | } |
623 | |
624 | /****************************** PROTECTED METHODS ****************************/ |
625 | |
626 | Event::List CalendarResources::rawEventsForDate( const QDate &date, |
627 | const KDateTime::Spec &timeSpec, |
628 | EventSortField sortField, |
629 | SortDirection sortDirection ) |
630 | { |
631 | Event::List result; |
632 | CalendarResourceManager::ActiveIterator it; |
633 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
634 | d->appendIncidences<Event::List>( result, |
635 | (*it)->rawEventsForDate( date, timeSpec ), *it ); |
636 | } |
637 | return sortEventsForDate( &result, date, timeSpec, sortField, sortDirection ); |
638 | } |
639 | |
640 | Event::List CalendarResources::rawEvents( const QDate &start, const QDate &end, |
641 | const KDateTime::Spec &timeSpec, bool inclusive ) |
642 | { |
643 | Event::List result; |
644 | CalendarResourceManager::ActiveIterator it; |
645 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
646 | d->appendIncidences<Event::List>( result, |
647 | (*it)->rawEvents( start, end, timeSpec, inclusive ), *it ); |
648 | } |
649 | return result; |
650 | } |
651 | |
652 | Event::List CalendarResources::rawEventsForDate( const KDateTime &kdt ) |
653 | { |
654 | // @TODO: Remove the code duplication by the resourcemap iteration block. |
655 | Event::List result; |
656 | CalendarResourceManager::ActiveIterator it; |
657 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
658 | d->appendIncidences<Event::List>( result, |
659 | (*it)->rawEventsForDate( kdt ), *it ); |
660 | } |
661 | return result; |
662 | } |
663 | |
664 | Event::List CalendarResources::rawEvents( EventSortField sortField, |
665 | SortDirection sortDirection ) |
666 | { |
667 | Event::List result; |
668 | CalendarResourceManager::ActiveIterator it; |
669 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
670 | d->appendIncidences<Event::List>( result, |
671 | (*it)->rawEvents( EventSortUnsorted ), *it ); |
672 | } |
673 | return sortEvents( &result, sortField, sortDirection ); |
674 | } |
675 | |
676 | bool CalendarResources::addJournal( Journal *journal ) |
677 | { |
678 | return addIncidence( journal ); |
679 | } |
680 | |
681 | bool CalendarResources::addJournal( Journal *journal, ResourceCalendar *resource ) |
682 | { |
683 | return addIncidence( journal, resource ); |
684 | } |
685 | |
686 | bool CalendarResources::deleteJournal( Journal *journal ) |
687 | { |
688 | bool status; |
689 | if ( d->mResourceMap.find( journal ) != d->mResourceMap.end() ) { |
690 | status = d->mResourceMap[journal]->deleteJournal( journal ); |
691 | if ( status ) { |
692 | d->mPendingDeleteFromResourceMap = true; |
693 | } |
694 | } else { |
695 | CalendarResourceManager::ActiveIterator it; |
696 | status = false; |
697 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
698 | status = (*it)->deleteJournal( journal ) || status; |
699 | } |
700 | } |
701 | |
702 | setModified( status ); |
703 | return status; |
704 | } |
705 | |
706 | void CalendarResources::deleteAllJournals() |
707 | { |
708 | CalendarResourceManager::ActiveIterator it; |
709 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
710 | (*it)->deleteAllJournals(); |
711 | } |
712 | } |
713 | |
714 | Journal *CalendarResources::journal( const QString &uid ) |
715 | { |
716 | CalendarResourceManager::ActiveIterator it; |
717 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
718 | Journal *journal = (*it)->journal( uid ); |
719 | if ( journal ) { |
720 | d->mResourceMap[journal] = *it; |
721 | return journal; |
722 | } |
723 | } |
724 | |
725 | // Not found |
726 | return 0; |
727 | } |
728 | |
729 | Journal::List CalendarResources::rawJournals( JournalSortField sortField, |
730 | SortDirection sortDirection ) |
731 | { |
732 | Journal::List result; |
733 | CalendarResourceManager::ActiveIterator it; |
734 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
735 | d->appendIncidences<Journal::List>( result, |
736 | (*it)->rawJournals( JournalSortUnsorted ), *it ); |
737 | } |
738 | return sortJournals( &result, sortField, sortDirection ); |
739 | } |
740 | |
741 | Journal::List CalendarResources::rawJournalsForDate( const QDate &date ) |
742 | { |
743 | |
744 | Journal::List result; |
745 | |
746 | CalendarResourceManager::ActiveIterator it; |
747 | for ( it = d->mManager->activeBegin(); it != d->mManager->activeEnd(); ++it ) { |
748 | d->appendIncidences<Journal::List>( result, |
749 | (*it)->rawJournalsForDate( date ), *it ); |
750 | } |
751 | return result; |
752 | } |
753 | |
754 | //@cond PRIVATE |
755 | template< class IncidenceList > |
756 | void CalendarResources::Private::appendIncidences( IncidenceList &result, |
757 | const IncidenceList &, |
758 | ResourceCalendar *resource ) |
759 | { |
760 | result += extra; |
761 | for ( typename IncidenceList::ConstIterator it = extra.begin(); |
762 | it != extra.end(); |
763 | ++it ) { |
764 | mResourceMap[ *it ] = resource; |
765 | } |
766 | } |
767 | //@endcond |
768 | |
769 | void CalendarResources::connectResource( ResourceCalendar *resource ) |
770 | { |
771 | connect( resource, SIGNAL(resourceChanged(ResourceCalendar*)), |
772 | SIGNAL(calendarChanged()) ); |
773 | connect( resource, SIGNAL(resourceSaved(ResourceCalendar*)), |
774 | SIGNAL(calendarSaved()) ); |
775 | |
776 | connect( resource, SIGNAL(resourceLoadError(ResourceCalendar*,QString)), |
777 | SLOT(slotLoadError(ResourceCalendar*,QString)) ); |
778 | connect( resource, SIGNAL(resourceSaveError(ResourceCalendar*,QString)), |
779 | SLOT(slotSaveError(ResourceCalendar*,QString)) ); |
780 | } |
781 | |
782 | ResourceCalendar *CalendarResources::resource( Incidence *incidence ) |
783 | { |
784 | if ( d->mResourceMap.find( incidence ) != d->mResourceMap.end() ) { |
785 | return d->mResourceMap[ incidence ]; |
786 | } |
787 | return 0; |
788 | } |
789 | |
790 | void CalendarResources::resourceAdded( ResourceCalendar *resource ) |
791 | { |
792 | if ( !resource->isActive() ) { |
793 | return; |
794 | } |
795 | |
796 | if ( resource->open() ) { |
797 | resource->load(); |
798 | } |
799 | |
800 | connectResource( resource ); |
801 | |
802 | emit signalResourceAdded( resource ); |
803 | } |
804 | |
805 | void CalendarResources::resourceModified( ResourceCalendar *resource ) |
806 | { |
807 | emit signalResourceModified( resource ); |
808 | } |
809 | |
810 | void CalendarResources::resourceDeleted( ResourceCalendar *resource ) |
811 | { |
812 | emit signalResourceDeleted( resource ); |
813 | } |
814 | |
815 | void CalendarResources::doSetTimeSpec( const KDateTime::Spec &timeSpec ) |
816 | { |
817 | // set the timezone for all resources. Otherwise we'll have those terrible |
818 | // tz troubles ;-(( |
819 | CalendarResourceManager::Iterator i1; |
820 | for ( i1 = d->mManager->begin(); i1 != d->mManager->end(); ++i1 ) { |
821 | (*i1)->setTimeSpec( timeSpec ); |
822 | } |
823 | } |
824 | |
825 | CalendarResources::Ticket::Ticket( ResourceCalendar *resource ) |
826 | : d( new KCal::CalendarResources::Ticket::Private( resource ) ) |
827 | { |
828 | } |
829 | |
830 | CalendarResources::Ticket::~Ticket() |
831 | { |
832 | delete d; |
833 | } |
834 | |
835 | CalendarResources::Ticket *CalendarResources::requestSaveTicket( ResourceCalendar *resource ) |
836 | { |
837 | KABC::Lock *lock = resource->lock(); |
838 | if ( !lock ) { |
839 | return 0; |
840 | } |
841 | if ( lock->lock() ) { |
842 | return new Ticket( resource ); |
843 | } else { |
844 | return 0; |
845 | } |
846 | } |
847 | |
848 | ResourceCalendar *CalendarResources::Ticket::resource() const |
849 | { |
850 | return d->mResource; |
851 | } |
852 | |
853 | bool CalendarResources::save( Ticket *ticket, Incidence *incidence ) |
854 | { |
855 | if ( !ticket || !ticket->resource() ) { |
856 | return false; |
857 | } |
858 | |
859 | // @TODO: Check if the resource was changed at all. If not, don't save. |
860 | if ( ticket->resource()->save( incidence ) ) { |
861 | releaseSaveTicket( ticket ); |
862 | return true; |
863 | } |
864 | |
865 | return false; |
866 | } |
867 | |
868 | void CalendarResources::releaseSaveTicket( Ticket *ticket ) |
869 | { |
870 | ticket->resource()->lock()->unlock(); |
871 | delete ticket; |
872 | } |
873 | |
874 | bool CalendarResources::beginChange( Incidence *incidence ) |
875 | { |
876 | ResourceCalendar *r = resource( incidence ); |
877 | if ( !r ) { |
878 | r = d->mDestinationPolicy->destination( incidence ); |
879 | if ( !r ) { |
880 | kError() << "Unable to get destination resource." ; |
881 | return false; |
882 | } |
883 | d->mResourceMap[ incidence ] = r; |
884 | } |
885 | d->mPendingDeleteFromResourceMap = false; |
886 | |
887 | int count = incrementChangeCount( r ); |
888 | if ( count == 1 ) { |
889 | Ticket *ticket = requestSaveTicket( r ); |
890 | if ( !ticket ) { |
891 | kDebug() << "unable to get ticket." ; |
892 | decrementChangeCount( r ); |
893 | return false; |
894 | } else { |
895 | d->mTickets[ r ] = ticket; |
896 | } |
897 | } |
898 | |
899 | return true; |
900 | } |
901 | |
902 | bool CalendarResources::endChange( Incidence *incidence ) |
903 | { |
904 | ResourceCalendar *r = resource( incidence ); |
905 | if ( !r ) { |
906 | return false; |
907 | } |
908 | |
909 | int count = decrementChangeCount( r ); |
910 | |
911 | if ( d->mPendingDeleteFromResourceMap ) { |
912 | d->mResourceMap.remove( incidence ); |
913 | d->mPendingDeleteFromResourceMap = false; |
914 | } |
915 | |
916 | if ( count == 0 ) { |
917 | bool ok = save( d->mTickets[ r ], incidence ); |
918 | if ( ok ) { |
919 | d->mTickets.remove( r ); |
920 | } else { |
921 | return false; |
922 | } |
923 | } |
924 | |
925 | return true; |
926 | } |
927 | |
928 | void CalendarResources::beginAddingIncidences() |
929 | { |
930 | d->mAddingInProgress = true; |
931 | } |
932 | |
933 | void CalendarResources::endAddingIncidences() |
934 | { |
935 | d->mAddingInProgress = false; |
936 | d->mLastUsedResource = 0; |
937 | } |
938 | |
939 | int CalendarResources::incrementChangeCount( ResourceCalendar *r ) |
940 | { |
941 | if ( !d->mChangeCounts.contains( r ) ) { |
942 | d->mChangeCounts.insert( r, 0 ); |
943 | } |
944 | |
945 | int count = d->mChangeCounts[ r ]; |
946 | ++count; |
947 | d->mChangeCounts[ r ] = count; |
948 | |
949 | return count; |
950 | } |
951 | |
952 | int CalendarResources::decrementChangeCount( ResourceCalendar *r ) |
953 | { |
954 | if ( !d->mChangeCounts.contains( r ) ) { |
955 | kError() << "No change count for resource." ; |
956 | return 0; |
957 | } |
958 | |
959 | int count = d->mChangeCounts[ r ]; |
960 | --count; |
961 | if ( count < 0 ) { |
962 | kError() << "Can't decrement change count. It already is 0." ; |
963 | count = 0; |
964 | } |
965 | d->mChangeCounts[ r ] = count; |
966 | |
967 | return count; |
968 | } |
969 | |
970 | void CalendarResources::slotLoadError( ResourceCalendar *r, const QString &err ) |
971 | { |
972 | Q_UNUSED( r ); |
973 | emit signalErrorMessage( err ); |
974 | } |
975 | |
976 | void CalendarResources::slotSaveError( ResourceCalendar *r, const QString &err ) |
977 | { |
978 | Q_UNUSED( r ); |
979 | emit signalErrorMessage( err ); |
980 | } |
981 | |