2 Copyright (C) 2010 Bertjan Broeksema <broeksema@kde.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 As a special exception, permission is given to link this program
19 with any edition of Qt, and distribute the resulting executable,
20 without including the source code for Qt in the source distribution.
23 // NOTE: The code of the following methods is taken from
24 // kdepim/korganizer/calendarview.cpp:
25 // - makeIndependent (was incidence_unsub)
26 // - makeChildrenIndependent
28 #include "calendarutils.h"
31 #include "incidencechanger.h"
34 #include <KCalCore/Incidence>
36 #include <KLocalizedString>
37 #include <KMessageBox>
39 using namespace Akonadi
;
40 using namespace CalendarSupport
;
41 using namespace KCalCore
;
43 /// CalendarUtilsPrivate
47 QVector
<Item::Id
> children
;
50 explicit MultiChange( const Item
&parent
= Item() )
56 return parent
.isValid() && !children
.isEmpty();
60 namespace CalendarSupport
{
62 struct CalendarUtilsPrivate
66 CalendarUtilsPrivate( Calendar
*calendar
, CalendarUtils
*qq
);
67 void handleChangeFinish( const Akonadi::Item
&oldInc
,
68 const Akonadi::Item
&newInc
,
69 CalendarSupport::IncidenceChanger::WhatChanged
,
72 bool purgeCompletedSubTodos( const Akonadi::Item
&todoItem
, bool &allPurged
);
76 IncidenceChanger
*mChanger
;
77 MultiChange mMultiChange
;
80 CalendarUtils
*const q_ptr
;
81 Q_DECLARE_PUBLIC( CalendarUtils
)
86 CalendarUtilsPrivate::CalendarUtilsPrivate( Calendar
*calendar
, CalendarUtils
*qq
)
87 : mCalendar( calendar
),
88 mChanger( new IncidenceChanger( calendar
, qq
) ),
92 Q_ASSERT( mCalendar
);
95 SIGNAL(incidenceChangeFinished(Akonadi::Item
,Akonadi::Item
,CalendarSupport::IncidenceChanger::WhatChanged
,bool)),
96 SLOT(handleChangeFinish(Akonadi::Item
,Akonadi::Item
,CalendarSupport::IncidenceChanger::WhatChanged
,bool)) );
99 void CalendarUtilsPrivate::handleChangeFinish( const Akonadi::Item
&oldInc
,
100 const Akonadi::Item
&newInc
,
101 CalendarSupport::IncidenceChanger::WhatChanged
,
104 Q_Q( CalendarUtils
);
106 if ( mMultiChange
.inProgress() ) {
107 mMultiChange
.children
.remove( mMultiChange
.children
.indexOf( newInc
.id() ) );
108 mMultiChange
.success
= mMultiChange
.success
&& success
;
110 // Are we still in progress?
111 if ( !mMultiChange
.inProgress() ) {
112 const Akonadi::Item parent
= mMultiChange
.parent
;
113 const bool success
= mMultiChange
.success
;
115 // Reset the multi change.
116 mMultiChange
= MultiChange();
117 Q_ASSERT( !mMultiChange
.inProgress() );
120 kDebug() << "MultiChange finished";
121 emit q
->actionFinished( parent
);
123 kDebug() << "MultiChange failed";
124 emit q
->actionFailed( parent
, QString() );
129 kDebug() << "Change finished";
130 emit q
->actionFinished( newInc
);
132 kDebug() << "Change failed";
133 // TODO: Let incidence changer return a useful message.
134 emit q
->actionFailed( oldInc
, QString() );
139 bool CalendarUtilsPrivate::purgeCompletedSubTodos( const Akonadi::Item
&todoItem
, bool &allPurged
)
141 const Todo::Ptr todo
= CalendarSupport::todo( todoItem
);
146 bool deleteThisTodo
= true;
147 Akonadi::Item::List subTodos
= mCalendar
->findChildren( todoItem
);
148 foreach ( const Akonadi::Item
&item
, subTodos
) {
149 if ( CalendarSupport::hasTodo( item
) ) {
150 deleteThisTodo
&= purgeCompletedSubTodos( item
, allPurged
);
154 if ( deleteThisTodo
) {
155 if ( todo
->isCompleted() ) {
156 if ( !mChanger
->deleteIncidence( todoItem
, 0 ) ) {
160 deleteThisTodo
= false;
163 if ( todo
->isCompleted() ) {
167 return deleteThisTodo
;
172 CalendarUtils::CalendarUtils( Calendar
*calendar
, QObject
*parent
)
174 d_ptr( new CalendarUtilsPrivate( calendar
, this ) )
176 Q_ASSERT( calendar
);
179 CalendarUtils::~CalendarUtils()
184 Calendar
*CalendarUtils::calendar() const
186 Q_D( const CalendarUtils
);
190 bool CalendarUtils::makeIndependent( const Akonadi::Item
&item
)
192 Q_D( CalendarUtils
);
193 Q_ASSERT( item
.isValid() );
195 if ( d
->mChanger
->changeInProgress( item
.id() ) ) {
199 if ( d
->mMultiChange
.inProgress() && !d
->mMultiChange
.children
.contains( item
.id() ) ) {
203 const Incidence::Ptr inc
= CalendarSupport::incidence( item
);
204 if ( !inc
|| inc
->relatedTo().isEmpty() ) {
208 Incidence::Ptr
oldInc( inc
->clone() );
209 inc
->setRelatedTo( 0 );
210 // HACK: This is not a widget, so pass 0 for now
211 return d
->mChanger
->changeIncidence( oldInc
, item
,
212 CalendarSupport::IncidenceChanger::RELATION_MODIFIED
,
216 bool CalendarUtils::makeChildrenIndependent( const Akonadi::Item
&item
)
218 Q_D( CalendarUtils
);
219 Q_ASSERT( item
.isValid() );
221 // Is the current item being changed atm?
222 if ( d
->mChanger
->changeInProgress( item
.id() ) ) {
226 if ( d
->mMultiChange
.inProgress() ) {
230 const Incidence::Ptr inc
= CalendarSupport::incidence( item
);
231 const Akonadi::Item::List subIncs
= d
->mCalendar
->findChildren( item
);
233 if ( !inc
|| subIncs
.isEmpty() ) {
237 // First make sure that no changes are in progress for one of the incs
238 foreach ( const Item
&subInc
, subIncs
) {
239 if ( d
->mChanger
->changeInProgress( subInc
.id() ) ) {
244 d
->mMultiChange
= MultiChange( item
);
245 bool allStarted
= true;
246 foreach ( const Item
&subInc
, subIncs
) {
247 d
->mMultiChange
.children
.append( subInc
.id() );
248 allStarted
= allStarted
&& makeIndependent( subInc
);
251 Q_ASSERT( allStarted
); // OKay, maybe we should not assert here, but one or
252 // changes could have been started, so just returning
253 // false isn't suitable either.
258 /// Todo specific methods.
260 void CalendarUtils::purgeCompletedTodos()
262 Q_D( CalendarUtils
);
263 bool allDeleted
= true;
264 // startMultiModify( i18n( "Purging completed to-dos" ) );
265 Akonadi::Item::List todos
= calendar()->rawTodos();
266 Akonadi::Item::List rootTodos
;
267 Akonadi::Item::List::ConstIterator it
;
268 Akonadi::Item::List::ConstIterator end
= todos
.constEnd();
270 for ( it
= todos
.constBegin(); it
!= end
; ++it
) {
271 Todo::Ptr aTodo
= CalendarSupport::todo( *it
);
272 if ( aTodo
&& aTodo
->relatedTo().isEmpty() ) { // top level todo //REVIEW(AKONADI_PORT)
273 rootTodos
.append( *it
);
276 end
= rootTodos
.constEnd();
277 // now that we have a list of all root todos, check them and their children
278 for ( it
= rootTodos
.constBegin(); it
!= end
; ++it
) {
279 d
->purgeCompletedSubTodos( *it
, allDeleted
);
284 KMessageBox::information(
287 "Unable to purge to-dos with uncompleted children." ),
288 i18nc( "@title:window", "Delete To-do" ),
289 "UncompletedChildrenPurgeTodos" );
293 #include "calendarutils.moc"