1/*
2 Copyright (c) 2008 Volker Krause <vkrause@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 "agentinstancecreatejob.h"
21
22#include "agentinstance.h"
23#include "agentmanager.h"
24#include "agentmanager_p.h"
25#include "controlinterface.h"
26#include "dbusconnectionpool.h"
27#include "kjobprivatebase_p.h"
28#include "servermanager.h"
29
30#include <kdebug.h>
31#include <klocalizedstring.h>
32
33#include <QtCore/QTimer>
34
35#ifdef Q_OS_UNIX
36#include <sys/types.h>
37#include <signal.h>
38#endif
39
40using namespace Akonadi;
41
42#if defined(Q_WS_MAEMO_5)
43static const int safetyTimeout = 60000; // ms
44#else
45static const int safetyTimeout = 10000; // ms
46#endif
47
48namespace Akonadi {
49/**
50 * @internal
51 */
52class AgentInstanceCreateJobPrivate : public KJobPrivateBase
53{
54public:
55 AgentInstanceCreateJobPrivate(AgentInstanceCreateJob *parent)
56 : q(parent)
57 , parentWidget(0)
58 , safetyTimer(new QTimer(parent))
59 , doConfig(false)
60 , tooLate(false)
61 {
62 QObject::connect(AgentManager::self(), SIGNAL(instanceAdded(Akonadi::AgentInstance)),
63 q, SLOT(agentInstanceAdded(Akonadi::AgentInstance)));
64 QObject::connect(safetyTimer, SIGNAL(timeout()), q, SLOT(timeout()));
65 }
66
67 void agentInstanceAdded(const AgentInstance &instance)
68 {
69 if (agentInstance == instance && !tooLate) {
70 safetyTimer->stop();
71 if (doConfig) {
72 // return from dbus call first before doing the next one
73 QTimer::singleShot(0, q, SLOT(doConfigure()));
74 } else {
75 q->emitResult();
76 }
77 }
78 }
79
80 void doConfigure()
81 {
82 org::freedesktop::Akonadi::Agent::Control *agentControlIface =
83 new org::freedesktop::Akonadi::Agent::Control(ServerManager::agentServiceName(ServerManager::Agent, agentInstance.identifier()),
84 QLatin1String("/"), DBusConnectionPool::threadConnection(), q);
85 if (!agentControlIface || !agentControlIface->isValid()) {
86 delete agentControlIface;
87
88 q->setError(KJob::UserDefinedError);
89 q->setErrorText(i18n("Unable to access D-Bus interface of created agent."));
90 q->emitResult();
91 return;
92 }
93
94 q->connect(agentControlIface, SIGNAL(configurationDialogAccepted()),
95 q, SLOT(configurationDialogAccepted()));
96 q->connect(agentControlIface, SIGNAL(configurationDialogRejected()),
97 q, SLOT(configurationDialogRejected()));
98
99 agentInstance.configure(parentWidget);
100 }
101
102 void configurationDialogAccepted()
103 {
104 // The user clicked 'Ok' in the initial configuration dialog, so we assume
105 // he wants to keep the resource and the job is done.
106 q->emitResult();
107 }
108
109 void configurationDialogRejected()
110 {
111 // The user clicked 'Cancel' in the initial configuration dialog, so we assume
112 // he wants to abort the 'create new resource' job and the new resource will be
113 // removed again.
114 AgentManager::self()->removeInstance(agentInstance);
115
116 q->emitResult();
117 }
118
119 void timeout()
120 {
121 tooLate = true;
122 q->setError(KJob::UserDefinedError);
123 q->setErrorText(i18n("Agent instance creation timed out."));
124 q->emitResult();
125 }
126
127 void emitResult()
128 {
129 q->emitResult();
130 }
131
132 void doStart();
133
134 AgentInstanceCreateJob *q;
135 AgentType agentType;
136 QString agentTypeId;
137 AgentInstance agentInstance;
138 QWidget *parentWidget;
139 QTimer *safetyTimer;
140 bool doConfig;
141 bool tooLate;
142};
143
144}
145
146AgentInstanceCreateJob::AgentInstanceCreateJob(const AgentType &agentType, QObject *parent)
147 : KJob(parent)
148 , d(new AgentInstanceCreateJobPrivate(this))
149{
150 d->agentType = agentType;
151}
152
153AgentInstanceCreateJob::AgentInstanceCreateJob(const QString &typeId, QObject *parent)
154 : KJob(parent)
155 , d(new AgentInstanceCreateJobPrivate(this))
156{
157 d->agentTypeId = typeId;
158}
159
160AgentInstanceCreateJob::~ AgentInstanceCreateJob()
161{
162 delete d;
163}
164
165void AgentInstanceCreateJob::configure(QWidget *parent)
166{
167 d->parentWidget = parent;
168 d->doConfig = true;
169}
170
171AgentInstance AgentInstanceCreateJob::instance() const
172{
173 return d->agentInstance;
174}
175
176void AgentInstanceCreateJob::start()
177{
178 d->start();
179}
180
181void AgentInstanceCreateJobPrivate::doStart()
182{
183 if (!agentType.isValid() && !agentTypeId.isEmpty()) {
184 agentType = AgentManager::self()->type(agentTypeId);
185 }
186
187 if (!agentType.isValid()) {
188 q->setError(KJob::UserDefinedError);
189 q->setErrorText(i18n("Unable to obtain agent type '%1'.", agentTypeId));
190 QTimer::singleShot(0, q, SLOT(emitResult()));
191 return;
192 }
193
194 agentInstance = AgentManager::self()->d->createInstance(agentType);
195 if (!agentInstance.isValid()) {
196 q->setError(KJob::UserDefinedError);
197 q->setErrorText(i18n("Unable to create agent instance."));
198 QTimer::singleShot(0, q, SLOT(emitResult()));
199 } else {
200 int timeout = safetyTimeout;
201#ifdef Q_OS_UNIX
202 // Increate the timeout when valgrinding the agent, because that slows down things a log.
203 QString agentValgrind = QString::fromLocal8Bit(qgetenv("AKONADI_VALGRIND"));
204 if (!agentValgrind.isEmpty() && agentType.identifier().contains(agentValgrind)) {
205 timeout *= 15;
206 }
207
208 // change the timeout when debugging the agent, because we need time to start the debugger
209 const QString agentDebugging = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_WAIT"));
210 if (!agentDebugging.isEmpty()) {
211 // we are debugging
212 const QString agentDebuggingTimeout = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_TIMEOUT"));
213 if (agentDebuggingTimeout.isEmpty()) {
214 // use default value of 150 seconds (the same as "valgrinding", this has to be checked)
215 timeout = 15 * safetyTimeout;
216 } else {
217 // use own value
218 timeout = agentDebuggingTimeout.toInt();
219 }
220 }
221#endif
222 safetyTimer->start(timeout);
223 }
224}
225
226#include "moc_agentinstancecreatejob.cpp"
227