Akonadi

controlgui.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "controlgui.h"
8 #include "akonadiwidgets_debug.h"
9 #include "erroroverlay_p.h"
10 #include "selftestdialog.h"
11 #include "servermanager.h"
12 #include "ui_controlprogressindicator.h"
13 
14 #include <KLocalizedString>
15 
16 #include <QCoreApplication>
17 #include <QEventLoop>
18 #include <QFrame>
19 #include <QPointer>
20 #include <QTimer>
21 
22 using namespace Akonadi;
23 using namespace std::chrono_literals;
24 namespace Akonadi
25 {
26 namespace Internal
27 {
28 class ControlProgressIndicator : public QFrame
29 {
30  Q_OBJECT
31 public:
32  explicit ControlProgressIndicator(QWidget *parent = nullptr)
33  : QFrame(parent)
34  {
35  setWindowModality(Qt::ApplicationModal);
36  resize(400, 100);
37  setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
38  ui.setupUi(this);
39 
40  setFrameShadow(QFrame::Plain);
41  setFrameShape(QFrame::Box);
42  }
43 
44  void setMessage(const QString &msg)
45  {
46  ui.statusLabel->setText(msg);
47  }
48 
49  Ui::ControlProgressIndicator ui;
50 };
51 
52 class StaticControlGui : public ControlGui
53 {
54  Q_OBJECT
55 };
56 
57 } // namespace Internal
58 
59 Q_GLOBAL_STATIC(Internal::StaticControlGui, s_instance) // NOLINT(readability-redundant-member-init)
60 
61 /**
62  * @internal
63  */
64 class ControlGuiPrivate
65 {
66 public:
67  explicit ControlGuiPrivate(ControlGui *parent)
68  : mParent(parent)
69  , mProgressIndicator(nullptr)
70  {
71  }
72 
73  ~ControlGuiPrivate()
74  {
75  delete mProgressIndicator;
76  }
77 
78  void setupProgressIndicator(const QString &msg, QWidget *parent = nullptr)
79  {
80  if (!mProgressIndicator) {
81  mProgressIndicator = new Internal::ControlProgressIndicator(parent);
82  }
83 
84  mProgressIndicator->setMessage(msg);
85  }
86 
87  void createErrorOverlays()
88  {
89  for (QWidget *widget : std::as_const(mPendingOverlays)) {
90  if (widget) {
91  new ErrorOverlay(widget);
92  }
93  }
94  mPendingOverlays.clear();
95  }
96 
97  void cleanup()
98  {
99  // delete s_instance;
100  }
101 
102  bool exec();
103  void serverStateChanged(ServerManager::State state);
104 
105  QPointer<ControlGui> mParent;
106  QEventLoop *mEventLoop = nullptr;
108  QList<QPointer<QWidget>> mPendingOverlays;
109  bool mSuccess = false;
110 
111  bool mStarting = false;
112  bool mStopping = false;
113 };
114 
115 bool ControlGuiPrivate::exec()
116 {
117  if (mProgressIndicator) {
118  mProgressIndicator->show();
119  }
120  qCDebug(AKONADIWIDGETS_LOG) << "Starting/Stopping Akonadi (using an event loop).";
121  mEventLoop = new QEventLoop(mParent);
122  mEventLoop->exec();
123  mEventLoop->deleteLater();
124  mEventLoop = nullptr;
125 
126  if (!mSuccess) {
127  qCWarning(AKONADIWIDGETS_LOG) << "Could not start/stop Akonadi!";
128  if (mProgressIndicator && mStarting) {
129  QPointer<SelfTestDialog> dlg = new SelfTestDialog(mProgressIndicator->parentWidget());
130  dlg->exec();
131  delete dlg;
132  if (!mParent) {
133  return false;
134  }
135  }
136  }
137 
138  delete mProgressIndicator;
139  mProgressIndicator = nullptr;
140  mStarting = false;
141  mStopping = false;
142 
143  const bool rv = mSuccess;
144  mSuccess = false;
145  return rv;
146 }
147 
148 void ControlGuiPrivate::serverStateChanged(ServerManager::State state)
149 {
150  qCDebug(AKONADIWIDGETS_LOG) << "Server state changed to" << state;
151  if (mEventLoop && mEventLoop->isRunning()) {
152  // ignore transient states going into the right direction
153  if ((mStarting && (state == ServerManager::Starting || state == ServerManager::Upgrading)) || (mStopping && state == ServerManager::Stopping)) {
154  return;
155  }
156  mEventLoop->quit();
157  mSuccess = (mStarting && state == ServerManager::Running) || (mStopping && state == ServerManager::NotRunning);
158  }
159 }
160 
162  : d(new ControlGuiPrivate(this))
163 {
165  d->serverStateChanged(state);
166  });
167  // mProgressIndicator is a widget, so it better be deleted before the QApplication is deleted
168  // Otherwise we get a crash in QCursor code with Qt-4.5
171  d->cleanup();
172  });
173  }
174 }
175 
176 ControlGui::~ControlGui() = default;
177 
179 {
181  qCDebug(AKONADIWIDGETS_LOG) << "Server is currently being stopped, won't try to start it now";
182  return false;
183  }
184  if (ServerManager::isRunning() || s_instance->d->mEventLoop) {
185  qCDebug(AKONADIWIDGETS_LOG) << "Server is already running";
186  return true;
187  }
188  s_instance->d->mStarting = true;
189  if (!ServerManager::start()) {
190  qCDebug(AKONADIWIDGETS_LOG) << "ServerManager::start failed -> return false";
191  return false;
192  }
193  return s_instance->d->exec();
194 }
195 
197 {
199  return false;
200  }
201  if (!ServerManager::isRunning() || s_instance->d->mEventLoop) {
202  return true;
203  }
204  s_instance->d->mStopping = true;
205  if (!ServerManager::stop()) {
206  return false;
207  }
208  return s_instance->d->exec();
209 }
210 
212 {
213  if (ServerManager::isRunning()) {
214  if (!stop()) {
215  return false;
216  }
217  }
218  return start();
219 }
220 
222 {
223  s_instance->d->setupProgressIndicator(i18n("Starting Akonadi server..."), parent);
224  return start();
225 }
226 
228 {
229  s_instance->d->setupProgressIndicator(i18n("Stopping Akonadi server..."), parent);
230  return stop();
231 }
232 
234 {
235  if (ServerManager::isRunning()) {
236  if (!stop(parent)) {
237  return false;
238  }
239  }
240  return start(parent);
241 }
242 
244 {
245  s_instance->d->mPendingOverlays.append(widget);
246  // delay the overlay creation since we rely on widget being reparented
247  // correctly already
248  QTimer::singleShot(0s, s_instance, []() {
249  s_instance->d->createErrorOverlays();
250  });
251 }
252 
253 } // namespace Akonadi
254 
255 #include "controlgui.moc"
static void widgetNeedsAkonadi(QWidget *widget)
Disable the given widget when Akonadi is not operational and show an error overlay (given enough spac...
Definition: controlgui.cpp:243
static bool start()
Starts the server.
static State state()
Returns the state of the server.
static bool stop()
Stops the server.
@ Upgrading
Server is performing a database upgrade as part of a new startup.
Definition: servermanager.h:42
static bool restart()
Restarts the Akonadi server synchronously.
Definition: controlgui.cpp:211
@ Starting
Server was started but is not yet running.
Definition: servermanager.h:38
ApplicationModal
static ServerManager * self()
Returns the singleton instance of this class, for connecting to its signals.
void stateChanged(Akonadi::ServerManager::State state)
Emitted whenever the server state changes.
A dialog that checks the current status of the Akonadi system.
~ControlGui() override
Destroys the ControlGui object.
@ Running
Server is running and operational.
Definition: servermanager.h:39
static bool stop()
Stops the Akonadi server synchronously if it is currently running.
Definition: controlgui.cpp:196
Definition: item.h:32
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
Definition: control.cpp:28
FramelessWindowHint
@ NotRunning
Server is not running, could be no one started it yet or it failed to start.
Definition: servermanager.h:37
static bool start()
Starts the Akonadi server synchronously if it is not already running.
Definition: controlgui.cpp:178
QString i18n(const char *text, const TYPE &arg...)
static bool isRunning()
Checks if the server is available currently.
Provides methods to ControlGui the Akonadi server process.
Definition: controlgui.h:53
QCoreApplication * instance()
State
Enum for the various states the server can be in.
Definition: servermanager.h:36
ControlGui()
Creates the ControlGui object.
Definition: controlgui.cpp:161
@ Stopping
Server is shutting down.
Definition: servermanager.h:40
QObject * parent() const const
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Jun 27 2022 04:01:05 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.