File indexing completed on 2024-05-12 05:11:13
0001 /* 0002 This file is part of Akonadi Contact. 0003 0004 Copyright (c) 2009 - 2010 Tobias Koenig <tokoe@kde.org> 0005 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com> 0006 SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include "standardmailactionmanager.h" 0012 0013 #include "akonadi_mime_debug.h" 0014 #include "emptytrashcommand.h" 0015 #include "markascommand.h" 0016 #include "movetotrashcommand.h" 0017 #include "removeduplicatesjob.h" 0018 #include "specialmailcollections.h" 0019 #include "util_p.h" 0020 0021 #include <Akonadi/AgentFilterProxyModel> 0022 #include <Akonadi/AgentInstance> 0023 #include <Akonadi/AgentInstanceCreateJob> 0024 #include <Akonadi/AgentManager> 0025 #include <Akonadi/AgentTypeDialog> 0026 #include <Akonadi/CollectionStatistics> 0027 #include <Akonadi/EntityTreeModel> 0028 #include <Akonadi/MimeTypeChecker> 0029 #include <Akonadi/SubscriptionDialog> 0030 0031 #include "messagestatus.h" 0032 #include <KMime/KMimeMessage> 0033 0034 #include <KActionCollection> 0035 #include <QAction> 0036 0037 #include <KLocalizedString> 0038 0039 #include <QItemSelectionModel> 0040 0041 using namespace Akonadi; 0042 0043 class Akonadi::StandardMailActionManagerPrivate 0044 { 0045 public: 0046 StandardMailActionManagerPrivate(KActionCollection *actionCollection, QWidget *parentWidget, StandardMailActionManager *parent) 0047 : mActionCollection(actionCollection) 0048 , mParentWidget(parentWidget) 0049 , mParent(parent) 0050 { 0051 mGenericManager = new StandardActionManager(actionCollection, parentWidget); 0052 0053 QObject::connect( 0054 mGenericManager, 0055 &StandardActionManager::selectionsChanged, 0056 mParent, 0057 [this](const Collection::List &selectedCollections, const Collection::List &selectedFavoriteCollections, const Item::List &selectedItems) { 0058 // Optimization: pass along the lists to avoid recalculating them here 0059 updateActions(selectedCollections, selectedFavoriteCollections, selectedItems); 0060 }); 0061 0062 QObject::connect(mGenericManager, &StandardActionManager::actionStateUpdated, mParent, &StandardMailActionManager::actionStateUpdated); 0063 0064 mGenericManager->setMimeTypeFilter(QStringList() << KMime::Message::mimeType()); 0065 mGenericManager->setCapabilityFilter(QStringList() << QStringLiteral("Resource")); 0066 } 0067 0068 ~StandardMailActionManagerPrivate() 0069 { 0070 delete mGenericManager; 0071 } 0072 0073 void updateGenericAllActions() 0074 { 0075 updateGenericAction(StandardActionManager::CreateCollection); 0076 updateGenericAction(StandardActionManager::CopyCollections); 0077 updateGenericAction(StandardActionManager::DeleteCollections); 0078 updateGenericAction(StandardActionManager::SynchronizeCollections); 0079 updateGenericAction(StandardActionManager::CollectionProperties); 0080 updateGenericAction(StandardActionManager::CopyItems); 0081 updateGenericAction(StandardActionManager::Paste); 0082 updateGenericAction(StandardActionManager::DeleteItems); 0083 updateGenericAction(StandardActionManager::ManageLocalSubscriptions); 0084 updateGenericAction(StandardActionManager::AddToFavoriteCollections); 0085 updateGenericAction(StandardActionManager::RemoveFromFavoriteCollections); 0086 updateGenericAction(StandardActionManager::RenameFavoriteCollection); 0087 updateGenericAction(StandardActionManager::CopyCollectionToMenu); 0088 updateGenericAction(StandardActionManager::CopyItemToMenu); 0089 updateGenericAction(StandardActionManager::MoveItemToMenu); 0090 updateGenericAction(StandardActionManager::MoveCollectionToMenu); 0091 updateGenericAction(StandardActionManager::CutItems); 0092 updateGenericAction(StandardActionManager::CutCollections); 0093 updateGenericAction(StandardActionManager::CreateResource); 0094 updateGenericAction(StandardActionManager::DeleteResources); 0095 updateGenericAction(StandardActionManager::ResourceProperties); 0096 updateGenericAction(StandardActionManager::SynchronizeResources); 0097 updateGenericAction(StandardActionManager::ToggleWorkOffline); 0098 updateGenericAction(StandardActionManager::CopyCollectionToDialog); 0099 updateGenericAction(StandardActionManager::MoveCollectionToDialog); 0100 updateGenericAction(StandardActionManager::CopyItemToDialog); 0101 updateGenericAction(StandardActionManager::MoveItemToDialog); 0102 updateGenericAction(StandardActionManager::SynchronizeCollectionsRecursive); 0103 updateGenericAction(StandardActionManager::MoveCollectionsToTrash); 0104 updateGenericAction(StandardActionManager::MoveItemsToTrash); 0105 updateGenericAction(StandardActionManager::RestoreCollectionsFromTrash); 0106 updateGenericAction(StandardActionManager::RestoreItemsFromTrash); 0107 updateGenericAction(StandardActionManager::MoveToTrashRestoreCollection); 0108 updateGenericAction(StandardActionManager::MoveToTrashRestoreCollectionAlternative); 0109 updateGenericAction(StandardActionManager::MoveToTrashRestoreItem); 0110 updateGenericAction(StandardActionManager::MoveToTrashRestoreItemAlternative); 0111 updateGenericAction(StandardActionManager::SynchronizeFavoriteCollections); 0112 } 0113 0114 void updateGenericAction(StandardActionManager::Type type) 0115 { 0116 switch (type) { 0117 case Akonadi::StandardActionManager::CreateCollection: { 0118 QAction *act = mGenericManager->action(Akonadi::StandardActionManager::CreateCollection); 0119 act->setText(i18n("Add Folder...")); 0120 act->setWhatsThis(i18n("Add a new folder to the currently selected account.")); 0121 setHelpText(act, i18n("Add a new folder to the currently selected account.")); 0122 0123 mGenericManager->setContextText(StandardActionManager::CreateCollection, StandardActionManager::DialogTitle, i18nc("@title:window", "New Folder")); 0124 0125 mGenericManager->setContextText(StandardActionManager::CreateCollection, 0126 StandardActionManager::ErrorMessageText, 0127 ki18n("Could not create folder: %1")); 0128 0129 mGenericManager->setContextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle, i18n("Folder creation failed")); 0130 break; 0131 } 0132 case Akonadi::StandardActionManager::CopyCollections: 0133 mGenericManager->setActionText(Akonadi::StandardActionManager::CopyCollections, ki18np("Copy Folder", "Copy %1 Folders")); 0134 mGenericManager->action(Akonadi::StandardActionManager::CopyCollections)->setWhatsThis(i18n("Copy the selected folders to the clipboard.")); 0135 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::CopyCollections), i18n("Copy the selected folders to the clipboard.")); 0136 mGenericManager->setContextText(StandardActionManager::CollectionProperties, 0137 StandardActionManager::DialogTitle, 0138 ki18nc("@title:window", "Properties of Folder %1")); 0139 break; 0140 case Akonadi::StandardActionManager::DeleteCollections: 0141 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteCollections, ki18np("Delete Folder", "Delete %1 Folders")); 0142 mGenericManager->action(Akonadi::StandardActionManager::DeleteCollections)->setWhatsThis(i18n("Delete the selected folders from the account.")); 0143 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::DeleteCollections), i18n("Delete the selected folders from the account.")); 0144 mGenericManager->setContextText(StandardActionManager::DeleteCollections, 0145 StandardActionManager::MessageBoxText, 0146 ki18np("Do you really want to delete this folder and all its sub-folders?", 0147 "Do you really want to delete %1 folders and all their sub-folders?")); 0148 0149 mGenericManager->setContextText(StandardActionManager::DeleteCollections, 0150 StandardActionManager::MessageBoxTitle, 0151 ki18ncp("@title:window", "Delete folder?", "Delete folders?")); 0152 0153 mGenericManager->setContextText(StandardActionManager::DeleteCollections, 0154 StandardActionManager::ErrorMessageText, 0155 ki18n("Could not delete folder: %1")); 0156 0157 mGenericManager->setContextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle, i18n("Folder deletion failed")); 0158 0159 break; 0160 case Akonadi::StandardActionManager::SynchronizeCollections: 0161 mGenericManager->setActionText(Akonadi::StandardActionManager::SynchronizeCollections, ki18np("Update Folder", "Update Folders")); 0162 0163 mGenericManager->action(Akonadi::StandardActionManager::SynchronizeCollections)->setWhatsThis(i18n("Update the contents of the selected folders.")); 0164 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::SynchronizeCollections), i18n("Update the contents of the selected folders.")); 0165 break; 0166 case Akonadi::StandardActionManager::CutCollections: 0167 mGenericManager->setActionText(Akonadi::StandardActionManager::CutCollections, ki18np("Cut Folder", "Cut %1 Folders")); 0168 mGenericManager->action(Akonadi::StandardActionManager::CutCollections)->setWhatsThis(i18n("Cut the selected folders from the account.")); 0169 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::CutCollections), i18n("Cut the selected folders from the account.")); 0170 break; 0171 case Akonadi::StandardActionManager::CollectionProperties: 0172 mGenericManager->action(Akonadi::StandardActionManager::CollectionProperties)->setText(i18n("Folder Properties")); 0173 mGenericManager->action(Akonadi::StandardActionManager::CollectionProperties) 0174 ->setWhatsThis(i18n("Open a dialog to edit the properties of the selected folder.")); 0175 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::CollectionProperties), 0176 i18n("Open a dialog to edit the properties of the selected folder.")); 0177 break; 0178 case Akonadi::StandardActionManager::CopyItems: 0179 mGenericManager->setActionText(Akonadi::StandardActionManager::CopyItems, ki18np("Copy Message", "Copy %1 Messages")); 0180 mGenericManager->action(Akonadi::StandardActionManager::CopyItems)->setWhatsThis(i18n("Copy the selected messages to the clipboard.")); 0181 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::CopyItems), i18n("Copy the selected messages to the clipboard.")); 0182 break; 0183 case Akonadi::StandardActionManager::DeleteItems: 0184 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteItems, ki18np("Delete Message", "Delete %1 Messages")); 0185 mGenericManager->action(Akonadi::StandardActionManager::DeleteItems)->setWhatsThis(i18n("Delete the selected messages from the folder.")); 0186 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::DeleteItems), i18n("Delete the selected messages from the folder.")); 0187 mGenericManager->setContextText(StandardActionManager::DeleteItems, 0188 StandardActionManager::MessageBoxText, 0189 ki18np("Do you really want to delete the selected message?", "Do you really want to delete %1 messages?")); 0190 0191 mGenericManager->setContextText(StandardActionManager::DeleteItems, 0192 StandardActionManager::MessageBoxTitle, 0193 ki18ncp("@title:window", "Delete Message?", "Delete Messages?")); 0194 0195 mGenericManager->setContextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText, ki18n("Could not delete message: %1")); 0196 0197 mGenericManager->setContextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle, i18n("Message deletion failed")); 0198 break; 0199 case Akonadi::StandardActionManager::CutItems: 0200 mGenericManager->setActionText(Akonadi::StandardActionManager::CutItems, ki18np("Cut Message", "Cut %1 Messages")); 0201 mGenericManager->action(Akonadi::StandardActionManager::CutItems)->setWhatsThis(i18n("Cut the selected message from the folder.")); 0202 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::CutItems), i18n("Cut the selected message from the folder.")); 0203 break; 0204 case Akonadi::StandardActionManager::CreateResource: 0205 mGenericManager->action(Akonadi::StandardActionManager::CreateResource)->setText(i18n("Add &Account...")); 0206 mGenericManager->action(Akonadi::StandardActionManager::CreateResource) 0207 ->setWhatsThis(i18n("Add a new account<p>" 0208 "You will be presented with a dialog where you can select " 0209 "the type of the account that shall be added.</p>")); 0210 mGenericManager->setContextText(StandardActionManager::CreateResource, StandardActionManager::DialogTitle, i18nc("@title:window", "Add Account")); 0211 0212 mGenericManager->setContextText(StandardActionManager::CreateResource, 0213 StandardActionManager::ErrorMessageText, 0214 ki18n("Could not create account: %1")); 0215 0216 mGenericManager->setContextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle, i18n("Account creation failed")); 0217 break; 0218 case Akonadi::StandardActionManager::DeleteResources: 0219 mGenericManager->setActionText(Akonadi::StandardActionManager::DeleteResources, ki18np("&Delete Account", "&Delete %1 Accounts")); 0220 mGenericManager->action(Akonadi::StandardActionManager::DeleteResources) 0221 ->setWhatsThis(i18n("Delete the selected accounts<p>" 0222 "The currently selected accounts will be deleted, " 0223 "along with all the messages they contain.</p>")); 0224 mGenericManager->setContextText(StandardActionManager::DeleteResources, 0225 StandardActionManager::MessageBoxText, 0226 ki18np("Do you really want to delete this account?", "Do you really want to delete %1 accounts?")); 0227 0228 mGenericManager->setContextText(StandardActionManager::DeleteResources, 0229 StandardActionManager::MessageBoxTitle, 0230 ki18ncp("@title:window", "Delete Account?", "Delete Accounts?")); 0231 break; 0232 case Akonadi::StandardActionManager::ResourceProperties: 0233 mGenericManager->action(Akonadi::StandardActionManager::ResourceProperties)->setText(i18n("Account Properties...")); 0234 mGenericManager->action(Akonadi::StandardActionManager::ResourceProperties) 0235 ->setWhatsThis(i18n("Open a dialog to edit properties of the selected account.")); 0236 break; 0237 case Akonadi::StandardActionManager::SynchronizeResources: 0238 mGenericManager->setActionText(Akonadi::StandardActionManager::SynchronizeResources, ki18np("Update Account", "Update %1 Accounts")); 0239 mGenericManager->action(Akonadi::StandardActionManager::SynchronizeResources) 0240 ->setWhatsThis(i18n("Updates the content of all folders of the selected accounts.")); 0241 break; 0242 case Akonadi::StandardActionManager::SynchronizeCollectionsRecursive: 0243 mGenericManager->setActionText(Akonadi::StandardActionManager::SynchronizeCollectionsRecursive, 0244 ki18np("Update This Folder and All Its Subfolders", "Update These Folders and All Their Subfolders")); 0245 0246 mGenericManager->action(Akonadi::StandardActionManager::SynchronizeCollectionsRecursive) 0247 ->setWhatsThis(i18n("Update the contents of the selected folders and all their subfolders.")); 0248 setHelpText(mGenericManager->action(Akonadi::StandardActionManager::SynchronizeCollectionsRecursive), 0249 i18n("Update the contents of the selected folders and all their subfolders.")); 0250 break; 0251 case Akonadi::StandardActionManager::Paste: 0252 mGenericManager->setContextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageText, ki18n("Could not paste message: %1")); 0253 0254 mGenericManager->setContextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle, i18n("Paste failed")); 0255 break; 0256 default: 0257 break; 0258 } 0259 } 0260 0261 void setHelpText(QAction *act, const QString &text) 0262 { 0263 act->setStatusTip(text); 0264 act->setToolTip(text); 0265 if (act->whatsThis().isEmpty()) { 0266 act->setWhatsThis(text); 0267 } 0268 } 0269 0270 void updateActions() 0271 { 0272 const Akonadi::Item::List selectedItems = mGenericManager->selectedItems(); 0273 const Akonadi::Collection::List selectedCollections = mGenericManager->selectedCollections(); 0274 updateActions(selectedCollections, {}, selectedItems); 0275 } 0276 0277 void updateActionsFromSelectedItems(const Item::List &selectedItems) 0278 { 0279 const bool itemIsSelected = !selectedItems.isEmpty(); 0280 if (itemIsSelected) { 0281 bool allMarkedAsImportant = true; 0282 bool allMarkedAsRead = true; 0283 bool allMarkedAsUnread = true; 0284 bool allMarkedAsActionItem = true; 0285 0286 for (const Akonadi::Item &item : selectedItems) { 0287 Akonadi::MessageStatus status; 0288 status.setStatusFromFlags(item.flags()); 0289 if (!status.isImportant()) { 0290 allMarkedAsImportant = false; 0291 } 0292 if (!status.isRead()) { 0293 allMarkedAsRead = false; 0294 } else { 0295 allMarkedAsUnread = false; 0296 } 0297 if (!status.isToAct()) { 0298 allMarkedAsActionItem = false; 0299 } 0300 } 0301 0302 QAction *action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsRead); 0303 if (action) { 0304 updateMarkAction(action, allMarkedAsRead); 0305 action->setEnabled(!allMarkedAsRead); 0306 } 0307 0308 action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsUnread); 0309 if (action) { 0310 updateMarkAction(action, allMarkedAsUnread); 0311 action->setEnabled(!allMarkedAsUnread); 0312 } 0313 0314 action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsImportant); 0315 if (action) { 0316 action->setCheckable(true); 0317 updateMarkAction(action, allMarkedAsImportant); 0318 action->setChecked(allMarkedAsImportant); 0319 if (allMarkedAsImportant) { 0320 action->setText(i18n("Remove Important Mark")); 0321 } else { 0322 action->setText(i18n("&Mark Message as Important")); 0323 } 0324 action->setEnabled(true); 0325 } 0326 0327 action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsActionItem); 0328 if (action) { 0329 action->setCheckable(true); 0330 updateMarkAction(action, allMarkedAsActionItem); 0331 action->setChecked(allMarkedAsActionItem); 0332 if (allMarkedAsActionItem) { 0333 action->setText(i18n("Remove Action Item Mark")); 0334 } else { 0335 action->setText(i18n("&Mark Message as Action Item")); 0336 } 0337 action->setEnabled(true); 0338 } 0339 } else { 0340 QAction *action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsRead); 0341 if (action) { 0342 action->setEnabled(false); 0343 } 0344 0345 action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsImportant); 0346 if (action) { 0347 action->setEnabled(false); 0348 } 0349 0350 action = mActions.value(Akonadi::StandardMailActionManager::MarkMailAsActionItem); 0351 if (action) { 0352 action->setEnabled(false); 0353 } 0354 } 0355 } 0356 0357 void updateActions(const Collection::List &selectedCollections, const Collection::List &selectedFavoriteCollections, const Item::List &selectedItems) 0358 { 0359 Q_UNUSED(selectedFavoriteCollections) 0360 const bool itemIsSelected = !selectedItems.isEmpty(); 0361 const bool collectionIsSelected = !selectedCollections.isEmpty(); 0362 updateActionsFromSelectedItems(selectedItems); 0363 0364 bool enableMarkAllAsRead = false; 0365 bool enableMarkAllAsUnread = false; 0366 bool canDeleteItem = true; 0367 bool isSystemFolder = false; 0368 if (collectionIsSelected) { 0369 for (const Collection &collection : std::as_const(selectedCollections)) { 0370 if (collection.isValid()) { 0371 const Akonadi::CollectionStatistics stats = collection.statistics(); 0372 if (!enableMarkAllAsRead) { 0373 enableMarkAllAsRead = (stats.unreadCount() > 0); 0374 } 0375 if (!enableMarkAllAsUnread) { 0376 enableMarkAllAsUnread = (stats.count() != stats.unreadCount()); 0377 } 0378 if (canDeleteItem) { 0379 canDeleteItem = collection.rights() & Akonadi::Collection::CanDeleteItem; 0380 } 0381 if (!isSystemFolder) { 0382 isSystemFolder = (collection == SpecialMailCollections::self()->defaultCollection(SpecialMailCollections::Inbox) 0383 || collection == SpecialMailCollections::self()->defaultCollection(SpecialMailCollections::Outbox) 0384 || collection == SpecialMailCollections::self()->defaultCollection(SpecialMailCollections::SentMail) 0385 || collection == SpecialMailCollections::self()->defaultCollection(SpecialMailCollections::Trash) 0386 || collection == SpecialMailCollections::self()->defaultCollection(SpecialMailCollections::Drafts) 0387 || collection == SpecialMailCollections::self()->defaultCollection(SpecialMailCollections::Templates)); 0388 } 0389 // We will not change after that. 0390 if (enableMarkAllAsRead && enableMarkAllAsUnread && !canDeleteItem && isSystemFolder) { 0391 break; 0392 } 0393 } 0394 } 0395 } 0396 QAction *action = nullptr; 0397 if (isSystemFolder) { 0398 action = mGenericManager->action(StandardActionManager::DeleteCollections); 0399 if (action) { 0400 action->setEnabled(false); 0401 } 0402 } 0403 0404 action = mActions.value(Akonadi::StandardMailActionManager::MoveToTrash); 0405 if (action) { 0406 action->setEnabled(itemIsSelected && canDeleteItem); 0407 } 0408 action = mActions.value(Akonadi::StandardMailActionManager::RemoveDuplicates); 0409 if (action) { 0410 action->setEnabled(canDeleteItem); 0411 } 0412 0413 action = mActions.value(Akonadi::StandardMailActionManager::MarkAllMailAsRead); 0414 if (action) { 0415 action->setEnabled(enableMarkAllAsRead); 0416 } 0417 0418 action = mActions.value(Akonadi::StandardMailActionManager::MarkAllMailAsUnread); 0419 if (action) { 0420 action->setEnabled(enableMarkAllAsUnread); 0421 } 0422 0423 Q_EMIT mParent->actionStateUpdated(); 0424 } 0425 0426 void updateMarkAction(QAction *action, bool allMarked) 0427 { 0428 QByteArray data = action->data().toByteArray(); 0429 if (allMarked) { 0430 if (!data.startsWith('!')) { 0431 data.prepend('!'); 0432 } 0433 } else { 0434 if (data.startsWith('!')) { 0435 data.remove(0, 1); 0436 } 0437 } 0438 action->setData(data); 0439 } 0440 0441 void markItemsAs(QByteArray typeStr, const Akonadi::Item::List &items, bool checkIntercept = true) 0442 { 0443 qCDebug(AKONADIMIME_LOG) << "Mark mail as: " << typeStr; 0444 0445 bool invert = false; 0446 if (typeStr.startsWith('!')) { 0447 invert = true; 0448 typeStr.remove(0, 1); 0449 } 0450 0451 Akonadi::MessageStatus targetStatus; 0452 targetStatus.setStatusFromStr(QLatin1StringView(typeStr)); 0453 0454 StandardMailActionManager::Type type = StandardMailActionManager::MarkMailAsRead; 0455 if (typeStr == "U") { 0456 type = StandardMailActionManager::MarkMailAsUnread; 0457 targetStatus.setRead(true); 0458 invert = true; 0459 } else if (typeStr == "K") { 0460 type = StandardMailActionManager::MarkMailAsActionItem; 0461 } else if (typeStr == "G") { 0462 type = StandardMailActionManager::MarkMailAsImportant; 0463 } 0464 0465 if (mInterceptedActions.contains(type) && checkIntercept) { 0466 return; 0467 } 0468 0469 auto command = new MarkAsCommand(targetStatus, items, invert, mParent); 0470 command->execute(); 0471 } 0472 0473 void slotMarkAs() 0474 { 0475 const Akonadi::Item::List items = mGenericManager->selectedItems(); 0476 if (items.isEmpty()) { 0477 return; 0478 } 0479 const QAction *action = qobject_cast<QAction *>(mParent->sender()); 0480 Q_ASSERT(action); 0481 0482 const QByteArray typeStr = action->data().toByteArray(); 0483 0484 markItemsAs(typeStr, items, true); 0485 } 0486 0487 void markAllItemsAs(QByteArray typeStr, const Akonadi::Collection::List &collections, bool checkIntercept = true) 0488 { 0489 qCDebug(AKONADIMIME_LOG) << "Mark all as: " << typeStr; 0490 0491 Akonadi::MessageStatus targetStatus; 0492 targetStatus.setStatusFromStr(QLatin1StringView(typeStr)); 0493 0494 bool invert = false; 0495 if (typeStr.startsWith('!')) { 0496 invert = true; 0497 typeStr.remove(0, 1); 0498 } 0499 bool recursive = false; 0500 if (typeStr.startsWith(':')) { 0501 recursive = true; 0502 typeStr.remove(0, 1); 0503 } 0504 0505 StandardMailActionManager::Type type = StandardMailActionManager::MarkAllMailAsRead; 0506 if (typeStr == "U") { 0507 type = StandardMailActionManager::MarkAllMailAsUnread; 0508 targetStatus.setRead(true); 0509 invert = true; 0510 } else if (typeStr == "K") { 0511 type = StandardMailActionManager::MarkAllMailAsActionItem; 0512 } else if (typeStr == "G") { 0513 type = StandardMailActionManager::MarkAllMailAsImportant; 0514 } 0515 0516 if (mInterceptedActions.contains(type) && checkIntercept) { 0517 return; 0518 } 0519 0520 auto command = new MarkAsCommand(targetStatus, collections, invert, recursive, mParent); 0521 command->execute(); 0522 } 0523 0524 void slotMarkAllAs() 0525 { 0526 const Akonadi::Collection::List collections = mGenericManager->selectedCollections(); 0527 if (collections.isEmpty()) { 0528 return; 0529 } 0530 0531 const QAction *action = qobject_cast<QAction *>(mParent->sender()); 0532 Q_ASSERT(action); 0533 const QByteArray typeStr = action->data().toByteArray(); 0534 markAllItemsAs(typeStr, collections, true); 0535 } 0536 0537 void slotMoveToTrash() 0538 { 0539 if (mInterceptedActions.contains(StandardMailActionManager::MoveToTrash)) { 0540 return; 0541 } 0542 0543 if (mCollectionSelectionModel->selection().indexes().isEmpty()) { 0544 return; 0545 } 0546 0547 const Item::List items = mGenericManager->selectedItems(); 0548 if (items.isEmpty()) { 0549 return; 0550 } 0551 0552 auto command = new MoveToTrashCommand(mCollectionSelectionModel->model(), items, mParent); 0553 command->execute(); 0554 } 0555 0556 void slotMoveAllToTrash() 0557 { 0558 if (mInterceptedActions.contains(StandardMailActionManager::MoveAllToTrash)) { 0559 return; 0560 } 0561 0562 if (mCollectionSelectionModel->selection().indexes().isEmpty()) { 0563 return; 0564 } 0565 0566 const Collection::List collections = mGenericManager->selectedCollections(); 0567 if (collections.isEmpty()) { 0568 return; 0569 } 0570 0571 auto command = new MoveToTrashCommand(mCollectionSelectionModel->model(), collections, mParent); 0572 command->execute(); 0573 } 0574 0575 void slotRemoveDuplicates() 0576 { 0577 if (mInterceptedActions.contains(StandardMailActionManager::RemoveDuplicates)) { 0578 return; 0579 } 0580 0581 const Collection::List collections = mGenericManager->selectedCollections(); 0582 if (collections.isEmpty()) { 0583 return; 0584 } 0585 0586 auto job = new RemoveDuplicatesJob(collections, mParent); 0587 QObject::connect(job, &RemoveDuplicatesJob::finished, mParent, [this](KJob *job) { 0588 slotJobFinished(job); 0589 }); 0590 } 0591 0592 void slotJobFinished(KJob *job) 0593 { 0594 if (job->error()) { 0595 Util::showJobError(job); 0596 } 0597 } 0598 0599 void slotEmptyAllTrash() 0600 { 0601 if (mInterceptedActions.contains(StandardMailActionManager::EmptyAllTrash)) { 0602 return; 0603 } 0604 0605 auto command = new EmptyTrashCommand(const_cast<QAbstractItemModel *>(mCollectionSelectionModel->model()), mParent); 0606 command->execute(); 0607 } 0608 0609 void slotEmptyTrash() 0610 { 0611 if (mInterceptedActions.contains(StandardMailActionManager::EmptyTrash)) { 0612 return; 0613 } 0614 0615 if (mCollectionSelectionModel->selection().indexes().isEmpty()) { 0616 return; 0617 } 0618 0619 const Collection::List collections = mGenericManager->selectedCollections(); 0620 if (collections.count() != 1) { 0621 return; 0622 } 0623 0624 auto command = new EmptyTrashCommand(collections.first(), mParent); 0625 command->execute(); 0626 } 0627 0628 KActionCollection *const mActionCollection; 0629 QWidget *const mParentWidget; 0630 StandardActionManager *mGenericManager = nullptr; 0631 QItemSelectionModel *mCollectionSelectionModel = nullptr; 0632 QItemSelectionModel *mItemSelectionModel = nullptr; 0633 QHash<StandardMailActionManager::Type, QAction *> mActions; 0634 QSet<StandardMailActionManager::Type> mInterceptedActions; 0635 StandardMailActionManager *const mParent; 0636 }; 0637 0638 StandardMailActionManager::StandardMailActionManager(KActionCollection *actionCollection, QWidget *parent) 0639 : QObject(parent) 0640 , d(new StandardMailActionManagerPrivate(actionCollection, parent, this)) 0641 { 0642 } 0643 0644 StandardMailActionManager::~StandardMailActionManager() = default; 0645 0646 void StandardMailActionManager::setCollectionSelectionModel(QItemSelectionModel *selectionModel) 0647 { 0648 d->mCollectionSelectionModel = selectionModel; 0649 d->mGenericManager->setCollectionSelectionModel(selectionModel); 0650 0651 connect(selectionModel->model(), &QAbstractItemModel::rowsInserted, this, [this]() { 0652 d->updateActions(); 0653 }); 0654 connect(selectionModel->model(), &QAbstractItemModel::rowsRemoved, this, [this]() { 0655 d->updateActions(); 0656 }); 0657 // connecting to QItemSelectionModel::selectionChanged is done by mGenericManager 0658 0659 d->updateActions(); 0660 } 0661 0662 void StandardMailActionManager::setItems(const Item::List &selectedItems) 0663 { 0664 d->updateActionsFromSelectedItems(selectedItems); 0665 } 0666 0667 void StandardMailActionManager::setItemSelectionModel(QItemSelectionModel *selectionModel) 0668 { 0669 d->mItemSelectionModel = selectionModel; 0670 d->mGenericManager->setItemSelectionModel(selectionModel); 0671 0672 // connecting to QItemSelectionModel::selectionChanged is done by mGenericManager 0673 0674 // to catch item modifications, listen to the model's dataChanged signal as well 0675 connect(selectionModel->model(), &QAbstractItemModel::dataChanged, this, [this]() { 0676 d->updateActions(); 0677 }); 0678 0679 d->updateActions(); 0680 } 0681 0682 QAction *StandardMailActionManager::createAction(Type type) 0683 { 0684 if (d->mActions.contains(type)) { 0685 return d->mActions.value(type); 0686 } 0687 0688 QAction *action = nullptr; 0689 0690 switch (type) { 0691 case MarkMailAsRead: 0692 action = new QAction(d->mParentWidget); 0693 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-read"))); 0694 action->setText(i18n("&Mark Message as Read")); 0695 action->setIconText(i18n("Mark as Read")); 0696 d->setHelpText(action, i18n("Mark selected messages as read.")); 0697 action->setWhatsThis(i18n("Mark selected messages as read.")); 0698 d->mActions.insert(MarkMailAsRead, action); 0699 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_as_read"), action); 0700 action->setData(QByteArray("R")); 0701 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_R)); 0702 connect(action, &QAction::triggered, this, [this]() { 0703 d->slotMarkAs(); 0704 }); 0705 break; 0706 case MarkMailAsUnread: 0707 action = new QAction(d->mParentWidget); 0708 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-unread"))); 0709 action->setText(i18n("&Mark Message as Unread")); 0710 action->setIconText(i18n("Mark as Unread")); 0711 d->setHelpText(action, i18n("Mark selected messages as unread.")); 0712 action->setWhatsThis(i18n("Mark selected messages as unread.")); 0713 d->mActions.insert(MarkMailAsUnread, action); 0714 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_as_unread"), action); 0715 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_U)); 0716 action->setData(QByteArray("U")); 0717 connect(action, &QAction::triggered, this, [this]() { 0718 d->slotMarkAs(); 0719 }); 0720 break; 0721 case MarkMailAsImportant: 0722 action = new QAction(d->mParentWidget); 0723 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-important"))); 0724 action->setText(i18n("&Mark Message as Important")); 0725 action->setIconText(i18n("Mark as Important")); 0726 d->setHelpText(action, i18n("Mark selected messages as important.")); 0727 0728 d->mActions.insert(MarkMailAsImportant, action); 0729 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_as_important"), action); 0730 action->setData(QByteArray("G")); 0731 connect(action, &QAction::triggered, this, [this]() { 0732 d->slotMarkAs(); 0733 }); 0734 break; 0735 case MarkMailAsActionItem: 0736 action = new QAction(d->mParentWidget); 0737 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-task"))); 0738 action->setText(i18n("&Mark Message as Action Item")); 0739 action->setIconText(i18n("Mark as Action Item")); 0740 d->setHelpText(action, i18n("Mark selected messages as action items.")); 0741 action->setWhatsThis(i18n("Mark selected messages as action items.")); 0742 d->mActions.insert(MarkMailAsActionItem, action); 0743 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_as_action_item"), action); 0744 action->setData(QByteArray("K")); 0745 connect(action, &QAction::triggered, this, [this]() { 0746 d->slotMarkAs(); 0747 }); 0748 break; 0749 case MarkAllMailAsRead: 0750 action = new QAction(d->mParentWidget); 0751 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-read"))); 0752 action->setText(i18n("Mark &All Messages as Read")); 0753 action->setIconText(i18n("Mark All as Read")); 0754 d->setHelpText(action, i18n("Mark all messages as read.")); 0755 action->setWhatsThis(i18n("Mark all messages as read.")); 0756 d->mActions.insert(MarkAllMailAsRead, action); 0757 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_all_as_read"), action); 0758 action->setData(QByteArray("R")); 0759 connect(action, &QAction::triggered, this, [this]() { 0760 d->slotMarkAllAs(); 0761 }); 0762 break; 0763 case MarkAllMailAsReadRecursive: 0764 action = new QAction(d->mParentWidget); 0765 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-read"))); 0766 action->setText(i18n("Mark &All Messages as Read Recursively")); 0767 action->setIconText(i18n("Mark All as Read Recursively")); 0768 d->setHelpText(action, i18n("Mark all messages as read recursively.")); 0769 action->setWhatsThis(i18n("Mark all messages as read recursively.")); 0770 d->mActions.insert(MarkAllMailAsReadRecursive, action); 0771 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_all_as_read_recursive"), action); 0772 action->setData(QByteArray(":R")); 0773 connect(action, &QAction::triggered, this, [this]() { 0774 d->slotMarkAllAs(); 0775 }); 0776 break; 0777 case MarkAllMailAsUnread: 0778 action = new QAction(d->mParentWidget); 0779 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-unread"))); 0780 action->setText(i18n("Mark &All Messages as Unread")); 0781 action->setIconText(i18n("Mark All as Unread")); 0782 d->setHelpText(action, i18n("Mark all messages as unread.")); 0783 action->setWhatsThis(i18n("Mark all messages as unread.")); 0784 d->mActions.insert(MarkAllMailAsUnread, action); 0785 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_all_as_unread"), action); 0786 action->setData(QByteArray("U")); 0787 connect(action, &QAction::triggered, this, [this]() { 0788 d->slotMarkAllAs(); 0789 }); 0790 break; 0791 case MarkAllMailAsImportant: 0792 action = new QAction(d->mParentWidget); 0793 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-important"))); 0794 action->setText(i18n("Mark &All Messages as Important")); 0795 action->setIconText(i18n("Mark All as Important")); 0796 d->setHelpText(action, i18n("Mark all messages as important.")); 0797 action->setWhatsThis(i18n("Mark all messages as important.")); 0798 d->mActions.insert(MarkAllMailAsImportant, action); 0799 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_all_as_important"), action); 0800 action->setData(QByteArray("G")); 0801 connect(action, &QAction::triggered, this, [this]() { 0802 d->slotMarkAllAs(); 0803 }); 0804 break; 0805 case MarkAllMailAsActionItem: 0806 action = new QAction(d->mParentWidget); 0807 action->setIconText(i18n("Mark All as Action Item")); 0808 action->setText(i18n("Mark &All Messages as Action Item")); 0809 action->setIcon(QIcon::fromTheme(QStringLiteral("mail-mark-task"))); 0810 d->setHelpText(action, i18n("Mark all messages as action items.")); 0811 action->setWhatsThis(i18n("Mark all messages as action items.")); 0812 d->mActions.insert(MarkAllMailAsActionItem, action); 0813 d->mActionCollection->addAction(QStringLiteral("akonadi_mark_all_as_action_item"), action); 0814 action->setData(QByteArray("K")); 0815 connect(action, &QAction::triggered, this, [this]() { 0816 d->slotMarkAllAs(); 0817 }); 0818 break; 0819 case MoveToTrash: 0820 action = new QAction(d->mParentWidget); 0821 action->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); 0822 action->setText(i18n("Move to &Trash")); 0823 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::Key_Delete)); 0824 d->setHelpText(action, i18n("Move selected messages to the trash folder.")); 0825 action->setWhatsThis(i18n("Move selected messages to the trash folder.")); 0826 d->mActions.insert(MoveToTrash, action); 0827 d->mActionCollection->addAction(QStringLiteral("akonadi_move_to_trash"), action); 0828 connect(action, &QAction::triggered, this, [this]() { 0829 d->slotMoveToTrash(); 0830 }); 0831 break; 0832 case MoveAllToTrash: 0833 action = new QAction(d->mParentWidget); 0834 action->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); 0835 action->setText(i18n("Move All to &Trash")); 0836 d->setHelpText(action, i18n("Move all messages to the trash folder.")); 0837 action->setWhatsThis(i18n("Move all messages to the trash folder.")); 0838 d->mActions.insert(MoveAllToTrash, action); 0839 d->mActionCollection->addAction(QStringLiteral("akonadi_move_all_to_trash"), action); 0840 connect(action, &QAction::triggered, this, [this]() { 0841 d->slotMoveAllToTrash(); 0842 }); 0843 break; 0844 case RemoveDuplicates: 0845 action = new QAction(d->mParentWidget); 0846 action->setText(i18n("Remove &Duplicate Messages")); 0847 d->setHelpText(action, i18n("Remove duplicate messages.")); 0848 action->setWhatsThis(i18n("Remove duplicate messages.")); 0849 d->mActionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_Asterisk)); 0850 d->mActions.insert(RemoveDuplicates, action); 0851 d->mActionCollection->addAction(QStringLiteral("akonadi_remove_duplicates"), action); 0852 connect(action, &QAction::triggered, this, [this]() { 0853 d->slotRemoveDuplicates(); 0854 }); 0855 break; 0856 case EmptyAllTrash: 0857 action = new QAction(d->mParentWidget); 0858 action->setText(i18n("Empty All &Trash Folders")); 0859 d->setHelpText(action, i18n("Permanently delete all messages from all trash folders.")); 0860 action->setWhatsThis(i18n("Permanently delete all messages from all trash folders.")); 0861 d->mActions.insert(EmptyAllTrash, action); 0862 d->mActionCollection->addAction(QStringLiteral("akonadi_empty_all_trash"), action); 0863 connect(action, &QAction::triggered, this, [this]() { 0864 d->slotEmptyAllTrash(); 0865 }); 0866 break; 0867 case EmptyTrash: 0868 action = new QAction(d->mParentWidget); 0869 action->setText(i18n("E&mpty Trash")); 0870 d->setHelpText(action, i18n("Permanently delete all messages from the trash folder.")); 0871 action->setWhatsThis(i18n("Permanently delete all messages from the trash folder.")); 0872 d->mActions.insert(EmptyTrash, action); 0873 d->mActionCollection->addAction(QStringLiteral("akonadi_empty_trash"), action); 0874 connect(action, &QAction::triggered, this, [this]() { 0875 d->slotEmptyTrash(); 0876 }); 0877 break; 0878 default: 0879 Q_ASSERT(false); // should never happen 0880 break; 0881 } 0882 0883 return action; 0884 } 0885 0886 QAction *StandardMailActionManager::createAction(StandardActionManager::Type type) 0887 { 0888 QAction *act = d->mGenericManager->action(type); 0889 if (!act) { 0890 act = d->mGenericManager->createAction(type); 0891 } 0892 d->updateGenericAction(type); 0893 return act; 0894 } 0895 0896 void StandardMailActionManager::createAllActions() 0897 { 0898 createAction(MarkMailAsRead); 0899 createAction(MarkMailAsUnread); 0900 createAction(MarkMailAsImportant); 0901 createAction(MarkMailAsActionItem); 0902 createAction(MarkAllMailAsRead); 0903 createAction(MarkAllMailAsReadRecursive); 0904 createAction(MarkAllMailAsUnread); 0905 createAction(MarkAllMailAsImportant); 0906 createAction(MarkAllMailAsActionItem); 0907 createAction(MoveToTrash); 0908 createAction(MoveAllToTrash); 0909 createAction(RemoveDuplicates); 0910 createAction(EmptyAllTrash); 0911 createAction(EmptyTrash); 0912 0913 d->mGenericManager->createAllActions(); 0914 d->updateGenericAllActions(); 0915 0916 d->updateActions(); 0917 } 0918 0919 QAction *StandardMailActionManager::action(Type type) const 0920 { 0921 return d->mActions.value(type); 0922 } 0923 0924 QAction *StandardMailActionManager::action(StandardActionManager::Type type) const 0925 { 0926 return d->mGenericManager->action(type); 0927 } 0928 0929 void StandardMailActionManager::setActionText(StandardActionManager::Type type, const KLocalizedString &text) 0930 { 0931 d->mGenericManager->setActionText(type, text); 0932 } 0933 0934 void StandardMailActionManager::interceptAction(Type type, bool intercept) 0935 { 0936 if (intercept) { 0937 d->mInterceptedActions.insert(type); 0938 } else { 0939 d->mInterceptedActions.remove(type); 0940 } 0941 } 0942 0943 void StandardMailActionManager::interceptAction(StandardActionManager::Type type, bool intercept) 0944 { 0945 d->mGenericManager->interceptAction(type, intercept); 0946 } 0947 0948 Akonadi::Collection::List StandardMailActionManager::selectedCollections() const 0949 { 0950 return d->mGenericManager->selectedCollections(); 0951 } 0952 0953 Akonadi::Item::List StandardMailActionManager::selectedItems() const 0954 { 0955 return d->mGenericManager->selectedItems(); 0956 } 0957 0958 void StandardMailActionManager::setFavoriteCollectionsModel(FavoriteCollectionsModel *favoritesModel) 0959 { 0960 d->mGenericManager->setFavoriteCollectionsModel(favoritesModel); 0961 } 0962 0963 void StandardMailActionManager::setFavoriteSelectionModel(QItemSelectionModel *selectionModel) 0964 { 0965 d->mGenericManager->setFavoriteSelectionModel(selectionModel); 0966 } 0967 0968 void StandardMailActionManager::setCollectionPropertiesPageNames(const QStringList &names) 0969 { 0970 d->mGenericManager->setCollectionPropertiesPageNames(names); 0971 } 0972 0973 Akonadi::StandardActionManager *StandardMailActionManager::standardActionManager() const 0974 { 0975 return d->mGenericManager; 0976 } 0977 0978 void StandardMailActionManager::markItemsAs(const QByteArray &typeStr, const Item::List &items, bool checkIntercept) 0979 { 0980 d->markItemsAs(typeStr, items, checkIntercept); 0981 } 0982 0983 void StandardMailActionManager::markAllItemsAs(const QByteArray &typeStr, const Collection::List &collections, bool checkIntercept) 0984 { 0985 d->markAllItemsAs(typeStr, collections, checkIntercept); 0986 } 0987 0988 #include "moc_standardmailactionmanager.cpp"