File indexing completed on 2025-01-05 04:47:06

0001 /*
0002   SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "agentactionmanager.h"
0008 
0009 #include "agentfilterproxymodel.h"
0010 #include "agentinstancecreatejob.h"
0011 #include "agentinstancemodel.h"
0012 #include "agentmanager.h"
0013 #include "agenttypedialog.h"
0014 
0015 #include <KActionCollection>
0016 #include <KLocalizedString>
0017 #include <KMessageBox>
0018 #include <QAction>
0019 #include <QIcon>
0020 
0021 #include <KLazyLocalizedString>
0022 #include <QItemSelectionModel>
0023 #include <QPointer>
0024 
0025 using namespace Akonadi;
0026 
0027 /// @cond PRIVATE
0028 
0029 static const struct {
0030     const char *name;
0031     const KLazyLocalizedString label;
0032     const char *icon;
0033     int shortcut;
0034     const char *slot;
0035 } agentActionData[] = {{"akonadi_agentinstance_create", kli18n("&New Agent Instance..."), "folder-new", 0, SLOT(slotCreateAgentInstance())},
0036                        {"akonadi_agentinstance_delete", kli18n("&Delete Agent Instance"), "edit-delete", 0, SLOT(slotDeleteAgentInstance())},
0037                        {"akonadi_agentinstance_configure", kli18n("&Configure Agent Instance"), "configure", 0, SLOT(slotConfigureAgentInstance())}};
0038 static const int numAgentActionData = sizeof agentActionData / sizeof *agentActionData;
0039 
0040 static_assert(numAgentActionData == AgentActionManager::LastType, "agentActionData table does not match AgentActionManager types");
0041 
0042 /**
0043  * @internal
0044  */
0045 class Akonadi::AgentActionManagerPrivate
0046 {
0047 public:
0048     explicit AgentActionManagerPrivate(AgentActionManager *parent)
0049         : q(parent)
0050     {
0051         mActions.fill(nullptr, AgentActionManager::LastType);
0052 
0053         setContextText(AgentActionManager::CreateAgentInstance, AgentActionManager::DialogTitle, i18nc("@title:window", "New Agent Instance"));
0054 
0055         setContextText(AgentActionManager::CreateAgentInstance, AgentActionManager::ErrorMessageText, ki18n("Could not create agent instance: %1"));
0056 
0057         setContextText(AgentActionManager::CreateAgentInstance, AgentActionManager::ErrorMessageTitle, i18nc("@title:window", "Agent Instance Creation Failed"));
0058 
0059         setContextText(AgentActionManager::DeleteAgentInstance, AgentActionManager::MessageBoxTitle, i18nc("@title:window", "Delete Agent Instance?"));
0060 
0061         setContextText(AgentActionManager::DeleteAgentInstance,
0062                        AgentActionManager::MessageBoxText,
0063                        i18n("Do you really want to delete the selected agent instance?"));
0064     }
0065 
0066     void enableAction(AgentActionManager::Type type, bool enable)
0067     {
0068         Q_ASSERT(type >= 0 && type < AgentActionManager::LastType);
0069         if (QAction *act = mActions[type]) {
0070             act->setEnabled(enable);
0071         }
0072     }
0073 
0074     void updateActions()
0075     {
0076         const AgentInstance::List instances = selectedAgentInstances();
0077 
0078         const bool createActionEnabled = true;
0079         bool deleteActionEnabled = true;
0080         bool configureActionEnabled = true;
0081 
0082         if (instances.isEmpty()) {
0083             deleteActionEnabled = false;
0084             configureActionEnabled = false;
0085         }
0086 
0087         if (instances.count() == 1) {
0088             const AgentInstance &instance = instances.first();
0089             if (instance.type().capabilities().contains(QLatin1StringView("NoConfig"))) {
0090                 configureActionEnabled = false;
0091             }
0092         }
0093 
0094         enableAction(AgentActionManager::CreateAgentInstance, createActionEnabled);
0095         enableAction(AgentActionManager::DeleteAgentInstance, deleteActionEnabled);
0096         enableAction(AgentActionManager::ConfigureAgentInstance, configureActionEnabled);
0097 
0098         Q_EMIT q->actionStateUpdated();
0099     }
0100 
0101     AgentInstance::List selectedAgentInstances() const
0102     {
0103         AgentInstance::List instances;
0104 
0105         if (!mSelectionModel) {
0106             return instances;
0107         }
0108 
0109         const QModelIndexList lstModelIndex = mSelectionModel->selectedRows();
0110         for (const QModelIndex &index : lstModelIndex) {
0111             const auto instance = index.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
0112             if (instance.isValid()) {
0113                 instances << instance;
0114             }
0115         }
0116 
0117         return instances;
0118     }
0119 
0120     void slotCreateAgentInstance()
0121     {
0122         QPointer<Akonadi::AgentTypeDialog> dlg(new Akonadi::AgentTypeDialog(mParentWidget));
0123         dlg->setWindowTitle(contextText(AgentActionManager::CreateAgentInstance, AgentActionManager::DialogTitle));
0124 
0125         for (const QString &mimeType : std::as_const(mMimeTypeFilter)) {
0126             dlg->agentFilterProxyModel()->addMimeTypeFilter(mimeType);
0127         }
0128 
0129         for (const QString &capability : std::as_const(mCapabilityFilter)) {
0130             dlg->agentFilterProxyModel()->addCapabilityFilter(capability);
0131         }
0132 
0133         if (dlg->exec() == QDialog::Accepted) {
0134             const AgentType agentType = dlg->agentType();
0135 
0136             if (agentType.isValid()) {
0137                 auto job = new AgentInstanceCreateJob(agentType, q);
0138                 q->connect(job, &KJob::result, q, [this](KJob *job) {
0139                     slotAgentInstanceCreationResult(job);
0140                 });
0141                 job->configure(mParentWidget);
0142                 job->start();
0143             }
0144         }
0145         delete dlg;
0146     }
0147 
0148     void slotDeleteAgentInstance()
0149     {
0150         const AgentInstance::List instances = selectedAgentInstances();
0151         if (!instances.isEmpty()) {
0152             if (KMessageBox::questionTwoActions(mParentWidget,
0153                                                 contextText(AgentActionManager::DeleteAgentInstance, AgentActionManager::MessageBoxText),
0154                                                 contextText(AgentActionManager::DeleteAgentInstance, AgentActionManager::MessageBoxTitle),
0155                                                 KStandardGuiItem::del(),
0156                                                 KStandardGuiItem::cancel(),
0157                                                 QString(),
0158                                                 KMessageBox::Dangerous)
0159                 == KMessageBox::ButtonCode::PrimaryAction) {
0160                 for (const AgentInstance &instance : instances) {
0161                     AgentManager::self()->removeInstance(instance);
0162                 }
0163             }
0164         }
0165     }
0166 
0167     void slotConfigureAgentInstance()
0168     {
0169         AgentInstance::List instances = selectedAgentInstances();
0170         if (instances.isEmpty()) {
0171             return;
0172         }
0173 
0174         instances.first().configure(mParentWidget);
0175     }
0176 
0177     void slotAgentInstanceCreationResult(KJob *job)
0178     {
0179         if (job->error()) {
0180             KMessageBox::error(mParentWidget,
0181                                contextText(AgentActionManager::CreateAgentInstance, AgentActionManager::ErrorMessageText).arg(job->errorString()),
0182                                contextText(AgentActionManager::CreateAgentInstance, AgentActionManager::ErrorMessageTitle));
0183         }
0184     }
0185 
0186     void setContextText(AgentActionManager::Type type, AgentActionManager::TextContext context, const QString &data)
0187     {
0188         mContextTexts[type].insert(context, data);
0189     }
0190 
0191     void setContextText(AgentActionManager::Type type, AgentActionManager::TextContext context, const KLocalizedString &data)
0192     {
0193         mContextTexts[type].insert(context, data.toString());
0194     }
0195 
0196     QString contextText(AgentActionManager::Type type, AgentActionManager::TextContext context) const
0197     {
0198         return mContextTexts[type].value(context);
0199     }
0200 
0201     AgentActionManager *const q;
0202     KActionCollection *mActionCollection = nullptr;
0203     QWidget *mParentWidget = nullptr;
0204     QItemSelectionModel *mSelectionModel = nullptr;
0205     QList<QAction *> mActions;
0206     QStringList mMimeTypeFilter;
0207     QStringList mCapabilityFilter;
0208 
0209     using ContextTexts = QHash<AgentActionManager::TextContext, QString>;
0210     QHash<AgentActionManager::Type, ContextTexts> mContextTexts;
0211 };
0212 
0213 /// @endcond
0214 
0215 AgentActionManager::AgentActionManager(KActionCollection *actionCollection, QWidget *parent)
0216     : QObject(parent)
0217     , d(new AgentActionManagerPrivate(this))
0218 {
0219     d->mParentWidget = parent;
0220     d->mActionCollection = actionCollection;
0221 }
0222 
0223 AgentActionManager::~AgentActionManager() = default;
0224 
0225 void AgentActionManager::setSelectionModel(QItemSelectionModel *selectionModel)
0226 {
0227     d->mSelectionModel = selectionModel;
0228     connect(selectionModel, &QItemSelectionModel::selectionChanged, this, [this]() {
0229         d->updateActions();
0230     });
0231 }
0232 
0233 void AgentActionManager::setMimeTypeFilter(const QStringList &mimeTypes)
0234 {
0235     d->mMimeTypeFilter = mimeTypes;
0236 }
0237 
0238 void AgentActionManager::setCapabilityFilter(const QStringList &capabilities)
0239 {
0240     d->mCapabilityFilter = capabilities;
0241 }
0242 
0243 QAction *AgentActionManager::createAction(Type type)
0244 {
0245     Q_ASSERT(type >= 0 && type < LastType);
0246     Q_ASSERT(agentActionData[type].name);
0247     if (QAction *act = d->mActions[type]) {
0248         return act;
0249     }
0250 
0251     auto action = new QAction(d->mParentWidget);
0252     action->setText(agentActionData[type].label.toString());
0253 
0254     if (agentActionData[type].icon) {
0255         action->setIcon(QIcon::fromTheme(QString::fromLatin1(agentActionData[type].icon)));
0256     }
0257 
0258     action->setShortcut(agentActionData[type].shortcut);
0259 
0260     if (agentActionData[type].slot) {
0261         connect(action, SIGNAL(triggered()), agentActionData[type].slot);
0262     }
0263 
0264     d->mActionCollection->addAction(QString::fromLatin1(agentActionData[type].name), action);
0265     d->mActions[type] = action;
0266     d->updateActions();
0267 
0268     return action;
0269 }
0270 
0271 void AgentActionManager::createAllActions()
0272 {
0273     for (int type = 0; type < LastType; ++type) {
0274         auto action = createAction(static_cast<Type>(type));
0275         Q_UNUSED(action)
0276     }
0277 }
0278 
0279 QAction *AgentActionManager::action(Type type) const
0280 {
0281     Q_ASSERT(type >= 0 && type < LastType);
0282     return d->mActions[type];
0283 }
0284 
0285 void AgentActionManager::interceptAction(Type type, bool intercept)
0286 {
0287     Q_ASSERT(type >= 0 && type < LastType);
0288 
0289     const QAction *action = d->mActions[type];
0290 
0291     if (!action) {
0292         return;
0293     }
0294 
0295     if (intercept) {
0296         disconnect(action, SIGNAL(triggered()), this, agentActionData[type].slot);
0297     } else {
0298         connect(action, SIGNAL(triggered()), agentActionData[type].slot);
0299     }
0300 }
0301 
0302 AgentInstance::List AgentActionManager::selectedAgentInstances() const
0303 {
0304     return d->selectedAgentInstances();
0305 }
0306 
0307 void AgentActionManager::setContextText(Type type, TextContext context, const QString &text)
0308 {
0309     d->setContextText(type, context, text);
0310 }
0311 
0312 void AgentActionManager::setContextText(Type type, TextContext context, const KLocalizedString &text)
0313 {
0314     d->setContextText(type, context, text);
0315 }
0316 
0317 #include "moc_agentactionmanager.cpp"