1/*
2 Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "agentactionmanager.h"
21
22#include "agentfilterproxymodel.h"
23#include "agentinstancecreatejob.h"
24#include "agentinstancemodel.h"
25#include "agentmanager.h"
26#include "agenttypedialog.h"
27#include "metatypes.h"
28
29#include <KAction>
30#include <KIcon>
31#include <KActionCollection>
32#include <KDebug>
33#include <KLocalizedString>
34#include <KMessageBox>
35
36#include <QItemSelectionModel>
37#include <QPointer>
38
39#include <boost/static_assert.hpp>
40
41using namespace Akonadi;
42
43//@cond PRIVATE
44
45static const struct {
46 const char *name;
47 const char *label;
48 const char *icon;
49 int shortcut;
50 const char *slot;
51} agentActionData[] = {
52 { "akonadi_agentinstance_create", I18N_NOOP("&New Agent Instance..."),
53 "folder-new", 0, SLOT(slotCreateAgentInstance())
54 },
55 { "akonadi_agentinstance_delete", I18N_NOOP("&Delete Agent Instance"),
56 "edit-delete", 0, SLOT(slotDeleteAgentInstance())
57 },
58 { "akonadi_agentinstance_configure", I18N_NOOP("&Configure Agent Instance"),
59 "configure", 0, SLOT(slotConfigureAgentInstance())
60 }
61};
62static const int numAgentActionData = sizeof agentActionData / sizeof * agentActionData;
63
64BOOST_STATIC_ASSERT(numAgentActionData == AgentActionManager::LastType);
65
66/**
67 * @internal
68 */
69class AgentActionManager::Private
70{
71public:
72 Private(AgentActionManager *parent)
73 : q(parent)
74 , mSelectionModel(0)
75 {
76 mActions.fill(0, AgentActionManager::LastType);
77
78 setContextText(AgentActionManager::CreateAgentInstance,
79 AgentActionManager::DialogTitle,
80 i18nc("@title:window", "New Agent Instance"));
81
82 setContextText(AgentActionManager::CreateAgentInstance,
83 AgentActionManager::ErrorMessageText,
84 ki18n("Could not create agent instance: %1"));
85
86 setContextText(AgentActionManager::CreateAgentInstance,
87 AgentActionManager::ErrorMessageTitle,
88 i18n("Agent instance creation failed"));
89
90 setContextText(AgentActionManager::DeleteAgentInstance,
91 AgentActionManager::MessageBoxTitle,
92 i18nc("@title:window", "Delete Agent Instance?"));
93
94 setContextText(AgentActionManager::DeleteAgentInstance,
95 AgentActionManager::MessageBoxText,
96 i18n("Do you really want to delete the selected agent instance?"));
97 }
98
99 void enableAction(AgentActionManager::Type type, bool enable)
100 {
101 Q_ASSERT(type >= 0 && type < AgentActionManager::LastType);
102 if (mActions[type]) {
103 mActions[type]->setEnabled(enable);
104 }
105 }
106
107 void updateActions()
108 {
109 const AgentInstance::List instances = selectedAgentInstances();
110
111 const bool createActionEnabled = true;
112 bool deleteActionEnabled = true;
113 bool configureActionEnabled = true;
114
115 if (instances.isEmpty()) {
116 deleteActionEnabled = false;
117 configureActionEnabled = false;
118 }
119
120 if (instances.count() == 1) {
121 const AgentInstance instance = instances.first();
122 if (instance.type().capabilities().contains(QLatin1String("NoConfig"))) {
123 configureActionEnabled = false;
124 }
125 }
126
127 enableAction(CreateAgentInstance, createActionEnabled);
128 enableAction(DeleteAgentInstance, deleteActionEnabled);
129 enableAction(ConfigureAgentInstance, configureActionEnabled);
130
131 emit q->actionStateUpdated();
132 }
133
134 AgentInstance::List selectedAgentInstances() const
135 {
136 AgentInstance::List instances;
137
138 if (!mSelectionModel) {
139 return instances;
140 }
141
142 foreach (const QModelIndex &index, mSelectionModel->selectedRows()) {
143 const AgentInstance instance =
144 index.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
145 if (instance.isValid()) {
146 instances << instance;
147 }
148 }
149
150 return instances;
151 }
152
153 void slotCreateAgentInstance()
154 {
155 QPointer<Akonadi::AgentTypeDialog> dlg(new Akonadi::AgentTypeDialog(mParentWidget));
156 dlg->setCaption(contextText(AgentActionManager::CreateAgentInstance,
157 AgentActionManager::DialogTitle));
158
159 foreach (const QString &mimeType, mMimeTypeFilter) {
160 dlg->agentFilterProxyModel()->addMimeTypeFilter(mimeType);
161 }
162
163 foreach (const QString &capability, mCapabilityFilter) {
164 dlg->agentFilterProxyModel()->addCapabilityFilter(capability);
165 }
166
167 if (dlg->exec() == QDialog::Accepted && dlg != 0) {
168 const AgentType agentType = dlg->agentType();
169
170 if (agentType.isValid()) {
171 AgentInstanceCreateJob *job = new AgentInstanceCreateJob(agentType, q);
172 q->connect(job, SIGNAL(result(KJob*)), SLOT(slotAgentInstanceCreationResult(KJob*)));
173 job->configure(mParentWidget);
174 job->start();
175 }
176 }
177 delete dlg;
178 }
179
180 void slotDeleteAgentInstance()
181 {
182 const AgentInstance::List instances = selectedAgentInstances();
183 if (!instances.isEmpty()) {
184 if (KMessageBox::questionYesNo(
185 mParentWidget,
186 contextText(AgentActionManager::DeleteAgentInstance,
187 AgentActionManager::MessageBoxText),
188 contextText(AgentActionManager::DeleteAgentInstance,
189 AgentActionManager::MessageBoxTitle),
190 KStandardGuiItem::del(),
191 KStandardGuiItem::cancel(),
192 QString(),
193 KMessageBox::Dangerous) == KMessageBox::Yes) {
194
195 foreach (const AgentInstance &instance, instances) {
196 AgentManager::self()->removeInstance(instance);
197 }
198 }
199 }
200 }
201
202 void slotConfigureAgentInstance()
203 {
204 AgentInstance::List instances = selectedAgentInstances();
205 if (instances.isEmpty()) {
206 return;
207 }
208
209 instances.first().configure(mParentWidget);
210 }
211
212 void slotAgentInstanceCreationResult(KJob *job)
213 {
214 if (job->error()) {
215 KMessageBox::error(
216 mParentWidget,
217 contextText(AgentActionManager::CreateAgentInstance,
218 AgentActionManager::ErrorMessageText).arg(job->errorString()),
219 contextText(AgentActionManager::CreateAgentInstance,
220 AgentActionManager::ErrorMessageTitle));
221 }
222 }
223
224 void setContextText(AgentActionManager::Type type,
225 AgentActionManager::TextContext context, const QString &data)
226 {
227 mContextTexts[type].insert(context, data);
228 }
229
230 void setContextText(AgentActionManager::Type type,
231 AgentActionManager::TextContext context, const KLocalizedString &data)
232 {
233
234 mContextTexts[type].insert(context, data.toString());
235 }
236
237 QString contextText(AgentActionManager::Type type,
238 AgentActionManager::TextContext context) const
239 {
240 return mContextTexts[type].value(context);
241 }
242
243 AgentActionManager *q;
244 KActionCollection *mActionCollection;
245 QWidget *mParentWidget;
246 QItemSelectionModel *mSelectionModel;
247 QVector<KAction *> mActions;
248 QStringList mMimeTypeFilter;
249 QStringList mCapabilityFilter;
250
251 typedef QHash<AgentActionManager::TextContext, QString> ContextTexts;
252 QHash<AgentActionManager::Type, ContextTexts> mContextTexts;
253};
254
255//@endcond
256
257AgentActionManager::AgentActionManager(KActionCollection *actionCollection, QWidget *parent)
258 : QObject(parent)
259 , d(new Private(this))
260{
261 d->mParentWidget = parent;
262 d->mActionCollection = actionCollection;
263}
264
265AgentActionManager::~AgentActionManager()
266{
267 delete d;
268}
269
270void AgentActionManager::setSelectionModel(QItemSelectionModel *selectionModel)
271{
272 d->mSelectionModel = selectionModel;
273 connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
274 SLOT(updateActions()));
275}
276
277void AgentActionManager::setMimeTypeFilter(const QStringList &mimeTypes)
278{
279 d->mMimeTypeFilter = mimeTypes;
280}
281
282void AgentActionManager::setCapabilityFilter(const QStringList &capabilities)
283{
284 d->mCapabilityFilter = capabilities;
285}
286
287KAction *AgentActionManager::createAction(Type type)
288{
289 Q_ASSERT(type >= 0 && type < LastType);
290 Q_ASSERT(agentActionData[type].name);
291 if (d->mActions[type]) {
292 return d->mActions[type];
293 }
294
295 KAction *action = new KAction(d->mParentWidget);
296 action->setText(i18n(agentActionData[type].label));
297
298 if (agentActionData[type].icon) {
299 action->setIcon(KIcon(QString::fromLatin1(agentActionData[type].icon)));
300 }
301
302 action->setShortcut(agentActionData[type].shortcut);
303
304 if (agentActionData[type].slot) {
305 connect(action, SIGNAL(triggered()), agentActionData[type].slot);
306 }
307
308 d->mActionCollection->addAction(QString::fromLatin1(agentActionData[type].name), action);
309 d->mActions[type] = action;
310 d->updateActions();
311
312 return action;
313}
314
315void AgentActionManager::createAllActions()
316{
317 for (int type = 0; type < LastType; ++type) {
318 createAction((Type)type);
319 }
320}
321
322KAction *AgentActionManager::action(Type type) const
323{
324 Q_ASSERT(type >= 0 && type < LastType);
325 return d->mActions[type];
326}
327
328void AgentActionManager::interceptAction(Type type, bool intercept)
329{
330 Q_ASSERT(type >= 0 && type < LastType);
331
332 const KAction *action = d->mActions[type];
333
334 if (!action) {
335 return;
336 }
337
338 if (intercept) {
339 disconnect(action, SIGNAL(triggered()), this, agentActionData[type].slot);
340 } else {
341 connect(action, SIGNAL(triggered()), agentActionData[type].slot);
342 }
343}
344
345AgentInstance::List AgentActionManager::selectedAgentInstances() const
346{
347 return d->selectedAgentInstances();
348}
349
350void AgentActionManager::setContextText(Type type, TextContext context, const QString &text)
351{
352 d->setContextText(type, context, text);
353}
354
355void AgentActionManager::setContextText(Type type, TextContext context,
356 const KLocalizedString &text)
357{
358 d->setContextText(type, context, text);
359}
360
361#include "moc_agentactionmanager.cpp"
362