File indexing completed on 2024-05-26 05:14:41
0001 /* 0002 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "controlgui.h" 0008 #include "akonadiwidgets_debug.h" 0009 #include "erroroverlay_p.h" 0010 #include "selftestdialog.h" 0011 #include "servermanager.h" 0012 #include "ui_controlprogressindicator.h" 0013 0014 #include <KLocalizedString> 0015 0016 #include <QCoreApplication> 0017 #include <QEventLoop> 0018 #include <QFrame> 0019 #include <QPointer> 0020 #include <QTimer> 0021 0022 using namespace Akonadi; 0023 using namespace std::chrono_literals; 0024 namespace Akonadi 0025 { 0026 namespace Internal 0027 { 0028 class ControlProgressIndicator : public QFrame 0029 { 0030 Q_OBJECT 0031 public: 0032 explicit ControlProgressIndicator(QWidget *parent = nullptr) 0033 : QFrame(parent) 0034 { 0035 setWindowModality(Qt::ApplicationModal); 0036 resize(400, 100); 0037 setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); 0038 ui.setupUi(this); 0039 0040 setFrameShadow(QFrame::Plain); 0041 setFrameShape(QFrame::Box); 0042 } 0043 0044 void setMessage(const QString &msg) 0045 { 0046 ui.statusLabel->setText(msg); 0047 } 0048 0049 Ui::ControlProgressIndicator ui; 0050 }; 0051 0052 class StaticControlGui : public ControlGui 0053 { 0054 Q_OBJECT 0055 }; 0056 0057 } // namespace Internal 0058 0059 Q_GLOBAL_STATIC(Internal::StaticControlGui, s_instance) // NOLINT(readability-redundant-member-init) 0060 0061 /** 0062 * @internal 0063 */ 0064 class ControlGuiPrivate 0065 { 0066 public: 0067 explicit ControlGuiPrivate(ControlGui *parent) 0068 : mParent(parent) 0069 , mProgressIndicator(nullptr) 0070 { 0071 } 0072 0073 ~ControlGuiPrivate() 0074 { 0075 delete mProgressIndicator; 0076 } 0077 0078 void setupProgressIndicator(const QString &msg, QWidget *parent = nullptr) 0079 { 0080 if (!mProgressIndicator) { 0081 mProgressIndicator = new Internal::ControlProgressIndicator(parent); 0082 } 0083 0084 mProgressIndicator->setMessage(msg); 0085 } 0086 0087 void createErrorOverlays() 0088 { 0089 for (QWidget *widget : std::as_const(mPendingOverlays)) { 0090 if (widget) { 0091 new ErrorOverlay(widget); 0092 } 0093 } 0094 mPendingOverlays.clear(); 0095 } 0096 0097 void cleanup() 0098 { 0099 // delete s_instance; 0100 } 0101 0102 bool exec(); 0103 void serverStateChanged(ServerManager::State state); 0104 0105 QPointer<ControlGui> mParent; 0106 QEventLoop *mEventLoop = nullptr; 0107 QPointer<Internal::ControlProgressIndicator> mProgressIndicator; 0108 QList<QPointer<QWidget>> mPendingOverlays; 0109 bool mSuccess = false; 0110 0111 bool mStarting = false; 0112 bool mStopping = false; 0113 }; 0114 0115 bool ControlGuiPrivate::exec() 0116 { 0117 if (mProgressIndicator) { 0118 mProgressIndicator->show(); 0119 } 0120 qCDebug(AKONADIWIDGETS_LOG) << "Starting/Stopping Akonadi (using an event loop)."; 0121 mEventLoop = new QEventLoop(mParent); 0122 mEventLoop->exec(); 0123 mEventLoop->deleteLater(); 0124 mEventLoop = nullptr; 0125 0126 if (!mSuccess) { 0127 qCWarning(AKONADIWIDGETS_LOG) << "Could not start/stop Akonadi!"; 0128 if (mProgressIndicator && mStarting) { 0129 QPointer<SelfTestDialog> dlg = new SelfTestDialog(mProgressIndicator->parentWidget()); 0130 dlg->exec(); 0131 delete dlg; 0132 if (!mParent) { 0133 return false; 0134 } 0135 } 0136 } 0137 0138 delete mProgressIndicator; 0139 mProgressIndicator = nullptr; 0140 mStarting = false; 0141 mStopping = false; 0142 0143 const bool rv = mSuccess; 0144 mSuccess = false; 0145 return rv; 0146 } 0147 0148 void ControlGuiPrivate::serverStateChanged(ServerManager::State state) 0149 { 0150 qCDebug(AKONADIWIDGETS_LOG) << "Server state changed to" << state; 0151 if (mEventLoop && mEventLoop->isRunning()) { 0152 // ignore transient states going into the right direction 0153 if ((mStarting && (state == ServerManager::Starting || state == ServerManager::Upgrading)) || (mStopping && state == ServerManager::Stopping)) { 0154 return; 0155 } 0156 mEventLoop->quit(); 0157 mSuccess = (mStarting && state == ServerManager::Running) || (mStopping && state == ServerManager::NotRunning); 0158 } 0159 } 0160 0161 ControlGui::ControlGui() 0162 : d(new ControlGuiPrivate(this)) 0163 { 0164 connect(ServerManager::self(), &ServerManager::stateChanged, this, [this](Akonadi::ServerManager::State state) { 0165 d->serverStateChanged(state); 0166 }); 0167 // mProgressIndicator is a widget, so it better be deleted before the QApplication is deleted 0168 // Otherwise we get a crash in QCursor code with Qt-4.5 0169 if (QCoreApplication::instance()) { 0170 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, [this]() { 0171 d->cleanup(); 0172 }); 0173 } 0174 } 0175 0176 ControlGui::~ControlGui() = default; 0177 0178 bool ControlGui::start() 0179 { 0180 if (ServerManager::state() == ServerManager::Stopping) { 0181 qCDebug(AKONADIWIDGETS_LOG) << "Server is currently being stopped, won't try to start it now"; 0182 return false; 0183 } 0184 if (ServerManager::isRunning() || s_instance->d->mEventLoop) { 0185 qCDebug(AKONADIWIDGETS_LOG) << "Server is already running"; 0186 return true; 0187 } 0188 s_instance->d->mStarting = true; 0189 if (!ServerManager::start()) { 0190 qCDebug(AKONADIWIDGETS_LOG) << "ServerManager::start failed -> return false"; 0191 return false; 0192 } 0193 return s_instance->d->exec(); 0194 } 0195 0196 bool ControlGui::stop() 0197 { 0198 if (ServerManager::state() == ServerManager::Starting) { 0199 return false; 0200 } 0201 if (!ServerManager::isRunning() || s_instance->d->mEventLoop) { 0202 return true; 0203 } 0204 s_instance->d->mStopping = true; 0205 if (!ServerManager::stop()) { 0206 return false; 0207 } 0208 return s_instance->d->exec(); 0209 } 0210 0211 bool ControlGui::restart() 0212 { 0213 if (ServerManager::isRunning()) { 0214 if (!stop()) { 0215 return false; 0216 } 0217 } 0218 return start(); 0219 } 0220 0221 bool ControlGui::start(QWidget *parent) 0222 { 0223 s_instance->d->setupProgressIndicator(i18n("Starting Akonadi server..."), parent); 0224 return start(); 0225 } 0226 0227 bool ControlGui::stop(QWidget *parent) 0228 { 0229 s_instance->d->setupProgressIndicator(i18n("Stopping Akonadi server..."), parent); 0230 return stop(); 0231 } 0232 0233 bool ControlGui::restart(QWidget *parent) 0234 { 0235 if (ServerManager::isRunning()) { 0236 if (!stop(parent)) { 0237 return false; 0238 } 0239 } 0240 return start(parent); 0241 } 0242 0243 void ControlGui::widgetNeedsAkonadi(QWidget *widget) 0244 { 0245 s_instance->d->mPendingOverlays.append(widget); 0246 // delay the overlay creation since we rely on widget being reparented 0247 // correctly already 0248 QTimer::singleShot(0s, s_instance, []() { 0249 s_instance->d->createErrorOverlays(); 0250 }); 0251 } 0252 0253 } // namespace Akonadi 0254 0255 #include "controlgui.moc" 0256 0257 #include "moc_controlgui.cpp"