File indexing completed on 2024-05-12 05:10:50

0001 /*
0002    SPDX-FileCopyrightText: 2013 Sérgio Martins <iamsergio@gmail.com>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "todopurger.h"
0008 #include "calendarutils.h"
0009 #include "fetchjobcalendar.h"
0010 #include "todopurger_p.h"
0011 
0012 #include <KCalendarCore/Todo>
0013 
0014 #include <KLocalizedString>
0015 using namespace Akonadi;
0016 
0017 TodoPurgerPrivate::TodoPurgerPrivate(TodoPurger *q)
0018     : q(q)
0019 {
0020 }
0021 
0022 void TodoPurgerPrivate::onCalendarLoaded(bool success, const QString &message)
0023 {
0024     if (success) {
0025         deleteTodos();
0026     } else {
0027         m_lastError = message;
0028         if (m_calendarOwnership) {
0029             m_calendar.clear();
0030         }
0031         Q_EMIT q->todosPurged(false, 0, 0);
0032     }
0033 }
0034 
0035 void TodoPurgerPrivate::onItemsDeleted(int changeId, const QList<Item::Id> &deletedItems, IncidenceChanger::ResultCode result, const QString &message)
0036 {
0037     if (changeId != m_currentChangeId) {
0038         return; // Not ours.
0039     }
0040 
0041     m_lastError = message;
0042     if (m_calendarOwnership) {
0043         m_calendar.clear();
0044     }
0045     Q_EMIT q->todosPurged(result == IncidenceChanger::ResultCodeSuccess, deletedItems.count(), m_ignoredItems);
0046 }
0047 
0048 void TodoPurgerPrivate::deleteTodos()
0049 {
0050     if (!m_changer) {
0051         q->setIncidenceChager(new IncidenceChanger(this));
0052         m_changer->setShowDialogsOnError(false);
0053         m_changer->setHistoryEnabled(false);
0054     }
0055 
0056     const bool oldShowdialogs = m_changer->showDialogsOnError();
0057     const bool oldGroupware = m_changer->groupwareCommunication();
0058     m_changer->setShowDialogsOnError(false);
0059     m_changer->setGroupwareCommunication(false);
0060 
0061     m_changer->startAtomicOperation(i18n("Purging completed to-dos"));
0062     const Akonadi::Item::List items = m_calendar->items();
0063     Akonadi::Item::List toDelete;
0064     m_ignoredItems = 0;
0065     for (const Akonadi::Item &item : items) {
0066         KCalendarCore::Todo::Ptr todo = CalendarUtils::todo(item);
0067 
0068         if (!todo || !todo->isCompleted()) {
0069             continue;
0070         }
0071 
0072         if (treeIsDeletable(todo)) {
0073             toDelete.append(item);
0074         } else {
0075             m_ignoredItems++;
0076         }
0077     }
0078 
0079     if (toDelete.isEmpty()) {
0080         if (m_calendarOwnership) {
0081             m_calendar.clear();
0082         }
0083         Q_EMIT q->todosPurged(true, 0, m_ignoredItems);
0084     } else {
0085         m_currentChangeId = m_changer->deleteIncidences(toDelete);
0086         Q_ASSERT(m_currentChangeId > 0);
0087     }
0088 
0089     m_changer->endAtomicOperation();
0090 
0091     m_changer->setShowDialogsOnError(oldShowdialogs);
0092     m_changer->setGroupwareCommunication(oldGroupware);
0093 }
0094 
0095 bool TodoPurgerPrivate::treeIsDeletable(const KCalendarCore::Todo::Ptr &todo)
0096 {
0097     Q_ASSERT(todo);
0098 
0099     if (!todo->isCompleted() || todo->isReadOnly()) {
0100         return false;
0101     }
0102 
0103     const KCalendarCore::Incidence::List children = m_calendar->childIncidences(todo->uid());
0104     if (children.isEmpty()) {
0105         return true;
0106     }
0107 
0108     for (const KCalendarCore::Incidence::Ptr &child : children) {
0109         KCalendarCore::Todo::Ptr childTodo = child.dynamicCast<KCalendarCore::Todo>();
0110 
0111         if (!childTodo) {
0112             return false; // This never happens
0113         }
0114 
0115         if (!treeIsDeletable(childTodo)) {
0116             return false;
0117         }
0118     }
0119 
0120     return true;
0121 }
0122 
0123 TodoPurger::TodoPurger(QObject *parent)
0124     : QObject(parent)
0125     , d(new TodoPurgerPrivate(this))
0126 {
0127 }
0128 
0129 TodoPurger::~TodoPurger() = default;
0130 
0131 void TodoPurger::setIncidenceChager(IncidenceChanger *changer)
0132 {
0133     d->m_changer = changer;
0134     d->m_currentChangeId = -1;
0135     if (changer) {
0136         connect(changer, &IncidenceChanger::deleteFinished, d.get(), &TodoPurgerPrivate::onItemsDeleted);
0137     }
0138 }
0139 
0140 void TodoPurger::setCalendar(const CalendarBase::Ptr &calendar)
0141 {
0142     d->m_calendar = calendar;
0143     d->m_calendarOwnership = calendar.isNull();
0144 }
0145 
0146 void TodoPurger::purgeCompletedTodos()
0147 {
0148     d->m_lastError.clear();
0149 
0150     if (d->m_calendar) {
0151         d->deleteTodos();
0152     } else {
0153         d->m_calendar = FetchJobCalendar::Ptr(new FetchJobCalendar(this));
0154         // clang-format off
0155         connect(d->m_calendar.data(), SIGNAL(loadFinished(bool,QString)), d.get(), SLOT(onCalendarLoaded(bool,QString)));
0156         // clang-format on
0157     }
0158 }
0159 
0160 QString TodoPurger::lastError() const
0161 {
0162     return d->m_lastError;
0163 }
0164 
0165 #include "moc_todopurger_p.cpp"
0166 
0167 #include "moc_todopurger.cpp"