File indexing completed on 2024-05-12 05:11:10
0001 /* 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com> 0003 SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #include "markascommand.h" 0009 #include "markascommandhelper_p.h" 0010 #include "util_p.h" 0011 #include <Akonadi/CollectionFetchJob> 0012 #include <Akonadi/ItemFetchJob> 0013 #include <Akonadi/ItemFetchScope> 0014 #include <Akonadi/ItemModifyJob> 0015 0016 #include <KLocalizedString> 0017 #include <KMessageBox> 0018 0019 using namespace Akonadi; 0020 0021 class Akonadi::MarkAsCommandPrivate 0022 { 0023 public: 0024 MarkAsCommandPrivate() = default; 0025 0026 Akonadi::Collection::List mFolders; 0027 Akonadi::Item::List mMessages; 0028 Akonadi::MessageStatus mTargetStatus; 0029 int mMarkJobCount = 0; 0030 int mFolderListJobCount = 0; 0031 int mInvertMark = 0; 0032 bool mRecursive = false; 0033 }; 0034 0035 MarkAsCommand::MarkAsCommand(Akonadi::MessageStatus targetStatus, const Akonadi::Item::List &msgList, bool invert, QObject *parent) 0036 : CommandBase(parent) 0037 , d(new Akonadi::MarkAsCommandPrivate()) 0038 { 0039 d->mInvertMark = invert; 0040 d->mMessages = msgList; 0041 d->mTargetStatus = targetStatus; 0042 d->mFolderListJobCount = 0; 0043 d->mMarkJobCount = 0; 0044 } 0045 0046 MarkAsCommand::MarkAsCommand(Akonadi::MessageStatus targetStatus, const Akonadi::Collection::List &folders, bool invert, bool recursive, QObject *parent) 0047 : CommandBase(parent) 0048 , d(new Akonadi::MarkAsCommandPrivate()) 0049 { 0050 d->mInvertMark = invert; 0051 d->mFolders = folders; 0052 d->mTargetStatus = targetStatus; 0053 d->mFolderListJobCount = d->mFolders.size(); 0054 d->mMarkJobCount = 0; 0055 d->mRecursive = recursive; 0056 } 0057 0058 MarkAsCommand::~MarkAsCommand() = default; 0059 0060 void MarkAsCommand::slotCollectionFetchDone(KJob *job) 0061 { 0062 if (job->error()) { 0063 Util::showJobError(job); 0064 emitResult(Failed); 0065 return; 0066 } 0067 0068 auto fjob = static_cast<Akonadi::CollectionFetchJob *>(job); 0069 d->mFolders += fjob->collections(); 0070 d->mFolderListJobCount = d->mFolders.size(); 0071 0072 // We have the subtree now so act as if we were passed the collections in ctor 0073 d->mRecursive = false; 0074 execute(); 0075 } 0076 0077 void MarkAsCommand::slotFetchDone(KJob *job) 0078 { 0079 d->mFolderListJobCount--; 0080 0081 if (job->error()) { 0082 // handle errors 0083 Util::showJobError(job); 0084 emitResult(Failed); 0085 return; 0086 } 0087 0088 auto fjob = static_cast<Akonadi::ItemFetchJob *>(job); 0089 d->mMessages.clear(); 0090 const auto items = fjob->items(); 0091 for (const Akonadi::Item &item : items) { 0092 Akonadi::MessageStatus status; 0093 status.setStatusFromFlags(item.flags()); 0094 if (d->mInvertMark) { 0095 if (status & d->mTargetStatus) { 0096 d->mMessages.append(item); 0097 } 0098 } else if (!(status & d->mTargetStatus)) { 0099 d->mMessages.append(item); 0100 } 0101 } 0102 if (d->mMessages.empty()) { 0103 if (d->mFolderListJobCount == 0) { 0104 emitResult(OK); 0105 return; 0106 } 0107 } else { 0108 markMessages(); 0109 } 0110 if (d->mFolderListJobCount > 0) { 0111 auto fetchJob = new Akonadi::ItemFetchJob(d->mFolders[d->mFolderListJobCount - 1], parent()); 0112 fetchJob->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); 0113 connect(fetchJob, &Akonadi::ItemFetchJob::result, this, &MarkAsCommand::slotFetchDone); 0114 } 0115 } 0116 0117 void MarkAsCommand::execute() 0118 { 0119 if (d->mRecursive && !d->mFolders.isEmpty()) { 0120 if (KMessageBox::questionTwoActions(qobject_cast<QWidget *>(parent()), 0121 i18n("Are you sure you want to mark all messages in this folder and all its subfolders?"), 0122 i18n("Mark All Recursively"), 0123 KGuiItem(i18nc("@action:button", "Mark All")), 0124 KStandardGuiItem::cancel()) 0125 == KMessageBox::ButtonCode::PrimaryAction) { 0126 auto job = new Akonadi::CollectionFetchJob(d->mFolders.constFirst()); 0127 connect(job, &Akonadi::CollectionFetchJob::result, this, &MarkAsCommand::slotCollectionFetchDone); 0128 } else { 0129 emitResult(Canceled); 0130 } 0131 } else if (!d->mFolders.isEmpty()) { 0132 // yes, we go backwards, shouldn't matter 0133 auto job = new Akonadi::ItemFetchJob(d->mFolders[d->mFolderListJobCount - 1], parent()); 0134 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); 0135 connect(job, &Akonadi::ItemFetchJob::result, this, &MarkAsCommand::slotFetchDone); 0136 } else if (!d->mMessages.isEmpty()) { 0137 d->mFolders << d->mMessages.first().parentCollection(); 0138 markMessages(); 0139 } else { 0140 emitResult(OK); 0141 } 0142 } 0143 0144 void MarkAsCommand::markMessages() 0145 { 0146 d->mMarkJobCount = 0; 0147 0148 QSet<QByteArray> flags = d->mTargetStatus.statusFlags(); 0149 Q_ASSERT(flags.size() == 1); 0150 Akonadi::Item::Flag flag; 0151 if (!flags.isEmpty()) { 0152 flag = *(flags.begin()); 0153 } 0154 0155 Akonadi::Item::List itemsToModify; 0156 for (const Akonadi::Item &it : std::as_const(d->mMessages)) { 0157 Akonadi::Item item(it); 0158 0159 // be careful to only change the flags we want to change, not to overwrite them 0160 // otherwise ItemModifyJob will not do what we expect 0161 if (d->mInvertMark) { 0162 if (item.hasFlag(flag)) { 0163 item.clearFlag(flag); 0164 itemsToModify.push_back(item); 0165 } 0166 } else { 0167 if (!item.hasFlag(flag)) { 0168 item.setFlag(flag); 0169 itemsToModify.push_back(item); 0170 } 0171 } 0172 } 0173 0174 d->mMarkJobCount++; 0175 if (itemsToModify.isEmpty()) { 0176 slotModifyItemDone(); // pretend we did something 0177 } else { 0178 auto helper = new Akonadi::MarkAsCommandHelper(this); 0179 helper->setItemsToModify(itemsToModify); 0180 connect(helper, &Akonadi::MarkAsCommandHelper::emitResult, this, &MarkAsCommand::slotHelperDone); 0181 helper->start(); 0182 } 0183 } 0184 0185 void MarkAsCommand::slotHelperDone(Akonadi::CommandBase::Result result) 0186 { 0187 d->mMarkJobCount--; 0188 if (result == Akonadi::CommandBase::Failed) { 0189 emitResult(Failed); 0190 } 0191 slotModifyItemDone(); 0192 } 0193 0194 void MarkAsCommand::slotModifyItemDone() 0195 { 0196 if (d->mMarkJobCount == 0 && d->mFolderListJobCount == 0) { 0197 emitResult(OK); 0198 } 0199 } 0200 0201 #include "moc_markascommand.cpp"