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 | |
36 | using namespace Akonadi; |
37 | |
38 | namespace Akonadi { |
39 | namespace Internal { |
40 | |
41 | class ControlProgressIndicator : public QFrame |
42 | { |
43 | public: |
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 | |
64 | class StaticControl : public Control |
65 | { |
66 | public: |
67 | StaticControl() |
68 | : Control() |
69 | { |
70 | } |
71 | }; |
72 | |
73 | } |
74 | |
75 | K_GLOBAL_STATIC(Internal::StaticControl, s_instance) |
76 | |
77 | /** |
78 | * @internal |
79 | */ |
80 | class Control::Private |
81 | { |
82 | public: |
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 | |
135 | bool 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 | |
169 | void 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 | |
182 | Control::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 | |
194 | Control::~Control() |
195 | { |
196 | delete d; |
197 | } |
198 | |
199 | bool 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 | |
217 | bool 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 | |
232 | bool Control::restart() |
233 | { |
234 | if (ServerManager::isRunning()) { |
235 | if (!stop()) { |
236 | return false; |
237 | } |
238 | } |
239 | return start(); |
240 | } |
241 | |
242 | bool Control::start(QWidget *parent) |
243 | { |
244 | s_instance->d->setupProgressIndicator(i18n("Starting Akonadi server..." ), parent); |
245 | return start(); |
246 | } |
247 | |
248 | bool Control::stop(QWidget *parent) |
249 | { |
250 | s_instance->d->setupProgressIndicator(i18n("Stopping Akonadi server..." ), parent); |
251 | return stop(); |
252 | } |
253 | |
254 | bool Control::restart(QWidget *parent) |
255 | { |
256 | if (ServerManager::isRunning()) { |
257 | if (!stop(parent)) { |
258 | return false; |
259 | } |
260 | } |
261 | return start(parent); |
262 | } |
263 | |
264 | void 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 | |