Akonadi Mime

markascommand.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>
3 SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#include "markascommand.h"
9#include "markascommandhelper_p.h"
10#include "util_p.h"
11#include <Akonadi/CollectionFetchJob>
12#include <Akonadi/ItemFetchJob>
13#include <Akonadi/ItemFetchScope>
14#include <Akonadi/ItemModifyJob>
15
16#include <KLocalizedString>
17#include <KMessageBox>
18
19using namespace Akonadi;
20
21class Akonadi::MarkAsCommandPrivate
22{
23public:
24 MarkAsCommandPrivate() = default;
25
27 Akonadi::Item::List mMessages;
28 Akonadi::MessageStatus mTargetStatus;
29 int mMarkJobCount = 0;
30 int mFolderListJobCount = 0;
31 int mInvertMark = 0;
32 bool mRecursive = false;
33};
34
35MarkAsCommand::MarkAsCommand(Akonadi::MessageStatus targetStatus, const Akonadi::Item::List &msgList, bool invert, QObject *parent)
36 : CommandBase(parent)
37 , d(new Akonadi::MarkAsCommandPrivate())
38{
39 d->mInvertMark = invert;
40 d->mMessages = msgList;
41 d->mTargetStatus = targetStatus;
42 d->mFolderListJobCount = 0;
43 d->mMarkJobCount = 0;
44}
45
46MarkAsCommand::MarkAsCommand(Akonadi::MessageStatus targetStatus, const Akonadi::Collection::List &folders, bool invert, bool recursive, QObject *parent)
47 : CommandBase(parent)
48 , d(new Akonadi::MarkAsCommandPrivate())
49{
50 d->mInvertMark = invert;
51 d->mFolders = folders;
52 d->mTargetStatus = targetStatus;
53 d->mFolderListJobCount = d->mFolders.size();
54 d->mMarkJobCount = 0;
55 d->mRecursive = recursive;
56}
57
58MarkAsCommand::~MarkAsCommand() = default;
59
60void MarkAsCommand::slotCollectionFetchDone(KJob *job)
61{
62 if (job->error()) {
63 Util::showJobError(job);
64 emitResult(Failed);
65 return;
66 }
67
68 auto fjob = static_cast<Akonadi::CollectionFetchJob *>(job);
69 d->mFolders += fjob->collections();
70 d->mFolderListJobCount = d->mFolders.size();
71
72 // We have the subtree now so act as if we were passed the collections in ctor
73 d->mRecursive = false;
74 execute();
75}
76
77void MarkAsCommand::slotFetchDone(KJob *job)
78{
79 d->mFolderListJobCount--;
80
81 if (job->error()) {
82 // handle errors
83 Util::showJobError(job);
84 emitResult(Failed);
85 return;
86 }
87
88 auto fjob = static_cast<Akonadi::ItemFetchJob *>(job);
89 d->mMessages.clear();
90 const auto items = fjob->items();
91 for (const Akonadi::Item &item : items) {
93 status.setStatusFromFlags(item.flags());
94 if (d->mInvertMark) {
95 if (status & d->mTargetStatus) {
96 d->mMessages.append(item);
97 }
98 } else if (!(status & d->mTargetStatus)) {
99 d->mMessages.append(item);
100 }
101 }
102 if (d->mMessages.empty()) {
103 if (d->mFolderListJobCount == 0) {
104 emitResult(OK);
105 return;
106 }
107 } else {
108 markMessages();
109 }
110 if (d->mFolderListJobCount > 0) {
111 auto fetchJob = new Akonadi::ItemFetchJob(d->mFolders[d->mFolderListJobCount - 1], parent());
112 fetchJob->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
113 connect(fetchJob, &Akonadi::ItemFetchJob::result, this, &MarkAsCommand::slotFetchDone);
114 }
115}
116
117void MarkAsCommand::execute()
118{
119 if (d->mRecursive && !d->mFolders.isEmpty()) {
120 if (KMessageBox::questionTwoActions(qobject_cast<QWidget *>(parent()),
121 i18n("Are you sure you want to mark all messages in this folder and all its subfolders?"),
122 i18n("Mark All Recursively"),
123 KGuiItem(i18nc("@action:button", "Mark All")),
125 == KMessageBox::ButtonCode::PrimaryAction) {
126 auto job = new Akonadi::CollectionFetchJob(d->mFolders.constFirst());
127 connect(job, &Akonadi::CollectionFetchJob::result, this, &MarkAsCommand::slotCollectionFetchDone);
128 } else {
129 emitResult(Canceled);
130 }
131 } else if (!d->mFolders.isEmpty()) {
132 // yes, we go backwards, shouldn't matter
133 auto job = new Akonadi::ItemFetchJob(d->mFolders[d->mFolderListJobCount - 1], parent());
134 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
135 connect(job, &Akonadi::ItemFetchJob::result, this, &MarkAsCommand::slotFetchDone);
136 } else if (!d->mMessages.isEmpty()) {
137 d->mFolders << d->mMessages.first().parentCollection();
138 markMessages();
139 } else {
140 emitResult(OK);
141 }
142}
143
144void MarkAsCommand::markMessages()
145{
146 d->mMarkJobCount = 0;
147
148 QSet<QByteArray> flags = d->mTargetStatus.statusFlags();
149 Q_ASSERT(flags.size() == 1);
151 if (!flags.isEmpty()) {
152 flag = *(flags.begin());
153 }
154
155 Akonadi::Item::List itemsToModify;
156 for (const Akonadi::Item &it : std::as_const(d->mMessages)) {
157 Akonadi::Item item(it);
158
159 // be careful to only change the flags we want to change, not to overwrite them
160 // otherwise ItemModifyJob will not do what we expect
161 if (d->mInvertMark) {
162 if (item.hasFlag(flag)) {
163 item.clearFlag(flag);
164 itemsToModify.push_back(item);
165 }
166 } else {
167 if (!item.hasFlag(flag)) {
168 item.setFlag(flag);
169 itemsToModify.push_back(item);
170 }
171 }
172 }
173
174 d->mMarkJobCount++;
175 if (itemsToModify.isEmpty()) {
176 slotModifyItemDone(); // pretend we did something
177 } else {
178 auto helper = new Akonadi::MarkAsCommandHelper(this);
179 helper->setItemsToModify(itemsToModify);
180 connect(helper, &Akonadi::MarkAsCommandHelper::emitResult, this, &MarkAsCommand::slotHelperDone);
181 helper->start();
182 }
183}
184
185void MarkAsCommand::slotHelperDone(Akonadi::CommandBase::Result result)
186{
187 d->mMarkJobCount--;
188 if (result == Akonadi::CommandBase::Failed) {
189 emitResult(Failed);
190 }
191 slotModifyItemDone();
192}
193
194void MarkAsCommand::slotModifyItemDone()
195{
196 if (d->mMarkJobCount == 0 && d->mFolderListJobCount == 0) {
197 emitResult(OK);
198 }
199}
200
201#include "moc_markascommand.cpp"
Akonadi KMime Message Status.
void setStatusFromFlags(const QSet< QByteArray > &flags)
Set the status as a whole e.g.
int error() const
void result(KJob *job)
Q_SCRIPTABLE CaptureState status()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
KGuiItem cancel()
bool isEmpty() const const
void push_back(parameter_type value)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
iterator begin()
bool isEmpty() const const
qsizetype size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:21:09 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.