1/*
2 Copyright (c) 2007 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 "control.h"
21#include "servermanager.h"
22#include "ui_controlprogressindicator.h"
23#include "selftestdialog_p.h"
24#include "erroroverlay_p.h"
25
26#include <kdebug.h>
27#include <kglobal.h>
28#include <klocalizedstring.h>
29
30#include <QtCore/QEventLoop>
31#include <QtCore/QCoreApplication>
32#include <QtCore/QTimer>
33#include <QtCore/QPointer>
34#include <QFrame>
35
36using namespace Akonadi;
37
38namespace Akonadi {
39namespace Internal {
40
41class ControlProgressIndicator : public QFrame
42{
43public:
44 ControlProgressIndicator(QWidget *parent = 0)
45 : QFrame(parent)
46 {
47 setWindowModality(Qt::ApplicationModal);
48 resize(400, 100);
49 setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
50 ui.setupUi(this);
51
52 setFrameShadow(QFrame::Plain);
53 setFrameShape(QFrame::Box);
54 }
55
56 void setMessage(const QString &msg)
57 {
58 ui.statusLabel->setText(msg);
59 }
60
61 Ui::ControlProgressIndicator ui;
62};
63
64class StaticControl : public Control
65{
66public:
67 StaticControl()
68 : Control()
69 {
70 }
71};
72
73}
74
75K_GLOBAL_STATIC(Internal::StaticControl, s_instance)
76
77/**
78 * @internal
79 */
80class Control::Private
81{
82public:
83 Private(Control *parent)
84 : mParent(parent)
85 , mEventLoop(0)
86 , mProgressIndicator(0)
87 , mSuccess(false)
88 , mStarting(false)
89 , mStopping(false)
90 {
91 }
92
93 ~Private()
94 {
95 delete mProgressIndicator;
96 }
97
98 void setupProgressIndicator(const QString &msg, QWidget *parent = 0)
99 {
100 if (!mProgressIndicator) {
101 mProgressIndicator = new Internal::ControlProgressIndicator(parent);
102 }
103
104 mProgressIndicator->setMessage(msg);
105 }
106
107 void createErrorOverlays()
108 {
109 foreach (QWidget *widget, mPendingOverlays) {
110 if (widget) {
111 new ErrorOverlay(widget);
112 }
113 }
114 mPendingOverlays.clear();
115 }
116
117 void cleanup()
118 {
119 s_instance.destroy();
120 }
121
122 bool exec();
123 void serverStateChanged(ServerManager::State state);
124
125 QPointer<Control> mParent;
126 QEventLoop *mEventLoop;
127 QPointer<Internal::ControlProgressIndicator> mProgressIndicator;
128 QList<QPointer<QWidget> > mPendingOverlays;
129 bool mSuccess;
130
131 bool mStarting;
132 bool mStopping;
133};
134
135bool Control::Private::exec()
136{
137 if (mProgressIndicator) {
138 mProgressIndicator->show();
139 }
140
141 kDebug() << "Starting/Stopping Akonadi (using an event loop).";
142 mEventLoop = new QEventLoop(mParent);
143 mEventLoop->exec();
144 mEventLoop->deleteLater();
145 mEventLoop = 0;
146
147 if (!mSuccess) {
148 kWarning() << "Could not start/stop Akonadi!";
149 if (mProgressIndicator && mStarting) {
150 QPointer<SelfTestDialog> dlg = new SelfTestDialog(mProgressIndicator->parentWidget());
151 dlg->exec();
152 delete dlg;
153 if (!mParent) {
154 return false;
155 }
156 }
157 }
158
159 delete mProgressIndicator;
160 mProgressIndicator = 0;
161 mStarting = false;
162 mStopping = false;
163
164 const bool rv = mSuccess;
165 mSuccess = false;
166 return rv;
167}
168
169void Control::Private::serverStateChanged(ServerManager::State state)
170{
171 kDebug() << state;
172 if (mEventLoop && mEventLoop->isRunning()) {
173 // ignore transient states going into the right direction
174 if ((mStarting && (state == ServerManager::Starting || state == ServerManager::Upgrading)) ||
175 (mStopping && state == ServerManager::Stopping))
176 return;
177 mEventLoop->quit();
178 mSuccess = (mStarting && state == ServerManager::Running) || (mStopping && state == ServerManager::NotRunning);
179 }
180}
181
182Control::Control()
183 : d(new Private(this))
184{
185 connect(ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)),
186 SLOT(serverStateChanged(Akonadi::ServerManager::State)));
187 // mProgressIndicator is a widget, so it better be deleted before the QApplication is deleted
188 // Otherwise we get a crash in QCursor code with Qt-4.5
189 if (QCoreApplication::instance()) {
190 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
191 }
192}
193
194Control::~Control()
195{
196 delete d;
197}
198
199bool Control::start()
200{
201 if (ServerManager::state() == ServerManager::Stopping) {
202 kDebug() << "Server is currently being stopped, wont try to start it now";
203 return false;
204 }
205 if (ServerManager::isRunning() || s_instance->d->mEventLoop) {
206 kDebug() << "Server is already running";
207 return true;
208 }
209 s_instance->d->mStarting = true;
210 if (!ServerManager::start()) {
211 kDebug() << "ServerManager::start failed -> return false";
212 return false;
213 }
214 return s_instance->d->exec();
215}
216
217bool Control::stop()
218{
219 if (ServerManager::state() == ServerManager::Starting) {
220 return false;
221 }
222 if (!ServerManager::isRunning() || s_instance->d->mEventLoop) {
223 return true;
224 }
225 s_instance->d->mStopping = true;
226 if (!ServerManager::stop()) {
227 return false;
228 }
229 return s_instance->d->exec();
230}
231
232bool Control::restart()
233{
234 if (ServerManager::isRunning()) {
235 if (!stop()) {
236 return false;
237 }
238 }
239 return start();
240}
241
242bool Control::start(QWidget *parent)
243{
244 s_instance->d->setupProgressIndicator(i18n("Starting Akonadi server..."), parent);
245 return start();
246}
247
248bool Control::stop(QWidget *parent)
249{
250 s_instance->d->setupProgressIndicator(i18n("Stopping Akonadi server..."), parent);
251 return stop();
252}
253
254bool Control::restart(QWidget *parent)
255{
256 if (ServerManager::isRunning()) {
257 if (!stop(parent)) {
258 return false;
259 }
260 }
261 return start(parent);
262}
263
264void Control::widgetNeedsAkonadi(QWidget *widget)
265{
266 s_instance->d->mPendingOverlays.append(widget);
267 // delay the overlay creation since we rely on widget being reparented
268 // correctly already
269 QTimer::singleShot(0, s_instance, SLOT(createErrorOverlays()));
270}
271
272}
273
274#include "moc_control.cpp"
275