Better wording
[kdepim.git] / calendarsupport / calendarutils.cpp
blob5a840fc26c38dc5fce3156072ce7349846c5f3a1
1 /*
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"
30 #include "calendar.h"
31 #include "incidencechanger.h"
32 #include "utils.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
45 struct MultiChange {
46 Item parent;
47 QVector<Item::Id> children;
48 bool success;
50 explicit MultiChange( const Item &parent = Item() )
51 : parent( parent ),
52 success( true )
55 bool inProgress() {
56 return parent.isValid() && !children.isEmpty();
60 namespace CalendarSupport {
62 struct CalendarUtilsPrivate
64 public:
65 /// Methods
66 CalendarUtilsPrivate( Calendar *calendar, CalendarUtils *qq );
67 void handleChangeFinish( const Akonadi::Item &oldInc,
68 const Akonadi::Item &newInc,
69 CalendarSupport::IncidenceChanger::WhatChanged,
70 bool success );
72 bool purgeCompletedSubTodos( const Akonadi::Item &todoItem, bool &allPurged );
74 /// Members
75 Calendar *mCalendar;
76 IncidenceChanger *mChanger;
77 MultiChange mMultiChange;
79 private:
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 ) ),
89 q_ptr( qq )
91 Q_Q( CalendarUtils );
92 Q_ASSERT( mCalendar );
94 q->connect( mChanger,
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,
102 bool success )
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() );
119 if ( success ) {
120 kDebug() << "MultiChange finished";
121 emit q->actionFinished( parent );
122 } else {
123 kDebug() << "MultiChange failed";
124 emit q->actionFailed( parent, QString() );
127 } else {
128 if ( success ) {
129 kDebug() << "Change finished";
130 emit q->actionFinished( newInc );
131 } else {
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 );
142 if ( !todo ) {
143 return true;
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 ) ) {
157 allPurged = false;
159 } else {
160 deleteThisTodo = false;
162 } else {
163 if ( todo->isCompleted() ) {
164 allPurged = false;
167 return deleteThisTodo;
170 /// CalendarUtils
172 CalendarUtils::CalendarUtils( Calendar *calendar, QObject *parent )
173 : QObject( parent ),
174 d_ptr( new CalendarUtilsPrivate( calendar, this ) )
176 Q_ASSERT( calendar );
179 CalendarUtils::~CalendarUtils()
181 delete d_ptr;
184 Calendar *CalendarUtils::calendar() const
186 Q_D( const CalendarUtils );
187 return d->mCalendar;
190 bool CalendarUtils::makeIndependent( const Akonadi::Item &item )
192 Q_D( CalendarUtils );
193 Q_ASSERT( item.isValid() );
195 if ( d->mChanger->changeInProgress( item.id() ) ) {
196 return false;
199 if ( d->mMultiChange.inProgress() && !d->mMultiChange.children.contains( item.id() ) ) {
200 return false;
203 const Incidence::Ptr inc = CalendarSupport::incidence( item );
204 if ( !inc || inc->relatedTo().isEmpty() ) {
205 return false;
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,
213 0 );
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() ) ) {
223 return false;
226 if ( d->mMultiChange.inProgress() ) {
227 return false;
230 const Incidence::Ptr inc = CalendarSupport::incidence( item );
231 const Akonadi::Item::List subIncs = d->mCalendar->findChildren( item );
233 if ( !inc || subIncs.isEmpty() ) {
234 return false;
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() ) ) {
240 return false;
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.
255 return true;
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 );
282 // endMultiModify();
283 if ( !allDeleted ) {
284 KMessageBox::information(
286 i18nc( "@info",
287 "Unable to purge to-dos with uncompleted children." ),
288 i18nc( "@title:window", "Delete To-do" ),
289 "UncompletedChildrenPurgeTodos" );
293 #include "calendarutils.moc"