Akonadi

erroroverlay.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "erroroverlay_p.h"
8#include "ui_erroroverlay.h"
9#if 0
10#include "selftestdialog_p.h"
11#endif
12
13#include <KLocalizedString>
14#include <KStandardGuiItem>
15#include <QIcon>
16
17#include <QEvent>
18#include <QPalette>
19
20using namespace Akonadi;
21
22/// @cond PRIVATE
23
24class ErrorOverlayStatic
25{
26public:
27 QList<QPair<QPointer<QWidget>, QPointer<QWidget>>> baseWidgets;
28};
29
30Q_GLOBAL_STATIC(ErrorOverlayStatic, sInstanceOverlay) // NOLINT(readability-redundant-member-init)
31
32// return true if o1 is a parent of o2
33static bool isParentOf(QWidget *o1, QWidget *o2)
34{
35 if (!o1 || !o2) {
36 return false;
37 }
38 if (o1 == o2) {
39 return true;
40 }
41 if (o2->isWindow()) {
42 return false;
43 }
44 return isParentOf(o1, o2->parentWidget());
45}
46
47ErrorOverlay::ErrorOverlay(QWidget *baseWidget, QWidget *parent)
48 : QWidget(parent ? parent : baseWidget->window())
49 , mBaseWidget(baseWidget)
50 , ui(new Ui::ErrorOverlay)
51{
52 Q_ASSERT(baseWidget);
53
54 mBaseWidgetIsParent = isParentOf(mBaseWidget, this);
55
56 // check existing overlays to detect cascading
57 for (QList<QPair<QPointer<QWidget>, QPointer<QWidget>>>::Iterator it = sInstanceOverlay->baseWidgets.begin(); it != sInstanceOverlay->baseWidgets.end();) {
58 if ((*it).first == nullptr || (*it).second == nullptr) {
59 // garbage collection
60 it = sInstanceOverlay->baseWidgets.erase(it);
61 continue;
62 }
63 if (isParentOf((*it).first, baseWidget)) {
64 // parent already has an overlay, kill ourselves
65 mBaseWidget = nullptr;
66 hide();
67 deleteLater();
68 return;
69 }
70 if (isParentOf(baseWidget, (*it).first)) {
71 // child already has overlay, kill that one
72 delete (*it).second;
73 it = sInstanceOverlay->baseWidgets.erase(it);
74 continue;
75 }
76 ++it;
77 }
78 sInstanceOverlay->baseWidgets.append(qMakePair(mBaseWidget, QPointer<QWidget>(this)));
79
81 mPreviousState = !mBaseWidget->testAttribute(Qt::WA_ForceDisabled);
82
83 ui->setupUi(this);
84 ui->notRunningIcon->setPixmap(qApp->windowIcon().pixmap(64));
85 ui->brokenIcon->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-error")).pixmap(64));
86 ui->progressIcon->setPixmap(qApp->windowIcon().pixmap(32));
87 ui->quitButton->setText(KStandardGuiItem::quit().text());
88 ui->detailsQuitButton->setText(KStandardGuiItem::quit().text());
89
90 ui->quitButton->hide();
91 ui->detailsQuitButton->hide();
92
93 connect(ui->startButton, &QAbstractButton::clicked, this, &ErrorOverlay::startClicked);
94 connect(ui->quitButton, &QAbstractButton::clicked, this, &ErrorOverlay::quitClicked);
95 connect(ui->detailsQuitButton, &QAbstractButton::clicked, this, &ErrorOverlay::quitClicked);
96 connect(ui->selfTestButton, &QAbstractButton::clicked, this, &ErrorOverlay::selfTestClicked);
97
99 mOverlayActive = (state == ServerManager::Running);
100 serverStateChanged(state);
101
102 connect(ServerManager::self(), &ServerManager::stateChanged, this, &ErrorOverlay::serverStateChanged);
103
104 QPalette p = palette();
105 p.setColor(backgroundRole(), QColor(0, 0, 0, 128));
106 p.setColor(foregroundRole(), Qt::white);
107 setPalette(p);
108 setAutoFillBackground(true);
109
110 mBaseWidget->installEventFilter(this);
111
112 reposition();
113}
114
115ErrorOverlay::~ErrorOverlay()
116{
117 if (mBaseWidget && !mBaseWidgetIsParent) {
118 mBaseWidget->setEnabled(mPreviousState);
119 }
120}
121
122void ErrorOverlay::reposition()
123{
124 if (!mBaseWidget) {
125 return;
126 }
127
128 // reparent to the current top level widget of the base widget if needed
129 // needed eg. in dock widgets
130 if (parentWidget() != mBaseWidget->window()) {
131 setParent(mBaseWidget->window());
132 }
133
134 // follow base widget visibility
135 // needed eg. in tab widgets
136 if (!mBaseWidget->isVisible()) {
137 hide();
138 return;
139 }
140 if (mOverlayActive) {
141 show();
142 }
143
144 // follow position changes
145 const QPoint topLevelPos = mBaseWidget->mapTo(window(), QPoint(0, 0));
146 const QPoint parentPos = parentWidget()->mapFrom(window(), topLevelPos);
147 move(parentPos);
148
149 // follow size changes
150 // TODO: hide/scale icon if we don't have enough space
151 resize(mBaseWidget->size());
152}
153
154bool ErrorOverlay::eventFilter(QObject *object, QEvent *event)
155{
156 if (object == mBaseWidget && mOverlayActive
157 && (event->type() == QEvent::Move || event->type() == QEvent::Resize || event->type() == QEvent::Show || event->type() == QEvent::Hide
158 || event->type() == QEvent::ParentChange)) {
159 reposition();
160 }
161 return QWidget::eventFilter(object, event);
162}
163
164void ErrorOverlay::startClicked()
165{
167 if (state == ServerManager::Running) {
168 serverStateChanged(state);
169 } else {
171 }
172}
173
174void ErrorOverlay::quitClicked()
175{
176 qApp->quit();
177}
178
179void ErrorOverlay::selfTestClicked()
180{
181#if 0
182 SelfTestDialog dlg;
183 dlg.exec();
184#endif
185}
186
187void ErrorOverlay::serverStateChanged(ServerManager::State state)
188{
189 if (!mBaseWidget) {
190 return;
191 }
192
193 if (state == ServerManager::Running) {
194 if (mOverlayActive) {
195 mOverlayActive = false;
196 hide();
197 if (!mBaseWidgetIsParent) {
198 mBaseWidget->setEnabled(mPreviousState);
199 }
200 }
201 } else if (!mOverlayActive) {
202 mOverlayActive = true;
203 if (mBaseWidget->isVisible()) {
204 show();
205 }
206
207 if (!mBaseWidgetIsParent) {
208 mPreviousState = !mBaseWidget->testAttribute(Qt::WA_ForceDisabled);
209 mBaseWidget->setEnabled(false);
210 }
211
212 reposition();
213 }
214
215 if (mOverlayActive) {
216 switch (state) {
218 ui->stackWidget->setCurrentWidget(ui->notRunningPage);
219 break;
221 ui->stackWidget->setCurrentWidget(ui->brokenPage);
222 if (!ServerManager::brokenReason().isEmpty()) {
223 ui->brokenDescription->setText(
224 i18nc("%1 is a reason why", "Cannot connect to the Personal information management service.\n\n%1", ServerManager::brokenReason()));
225 }
226 break;
228 ui->progressPage->setToolTip(i18nc("@info:tooltip", "Personal information management service is starting..."));
229 ui->progressDescription->setText(i18n("Personal information management service is starting..."));
230 ui->stackWidget->setCurrentWidget(ui->progressPage);
231 break;
233 ui->progressPage->setToolTip(i18nc("@info:tooltip", "Personal information management service is shutting down..."));
234 ui->progressDescription->setText(i18n("Personal information management service is shutting down..."));
235 ui->stackWidget->setCurrentWidget(ui->progressPage);
236 break;
238 ui->progressPage->setToolTip(i18nc("@info:tooltip", "Personal information management service is performing a database upgrade."));
239 ui->progressDescription->setText(
240 i18n("Personal information management service is performing a database upgrade.\n"
241 "This happens after a software update and is necessary to optimize performance.\n"
242 "Depending on the amount of personal information, this might take a few minutes."));
243 ui->stackWidget->setCurrentWidget(ui->progressPage);
244 break;
246 break;
247 }
248 }
249}
250
251/// @endcond
252
253#include "moc_erroroverlay_p.cpp"
A dialog that checks the current status of the Akonadi system.
static State state()
Returns the state of the server.
static QString brokenReason()
Returns the reason why the Server is broken, if known.
static bool start()
Starts the server.
State
Enum for the various states the server can be in.
@ Running
Server is running and operational.
@ Starting
Server was started but is not yet running.
@ Broken
Server is not operational and an error has been detected.
@ Upgrading
Server is performing a database upgrade as part of a new startup.
@ NotRunning
Server is not running, could be no one started it yet or it failed to start.
@ Stopping
Server is shutting down.
void stateChanged(Akonadi::ServerManager::State state)
Emitted whenever the server state changes.
static ServerManager * self()
Returns the singleton instance of this class, for connecting to its signals.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Helper integration between Akonadi and Qt.
KIOCORE_EXPORT CopyJob * move(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
QWidget * window(QObject *job)
KGuiItem quit()
void clicked(bool checked)
virtual int exec()
QIcon fromTheme(const QString &name)
void deleteLater()
void destroyed(QObject *obj)
virtual bool eventFilter(QObject *watched, QEvent *event)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
WA_ForceDisabled
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isWindow() const const
QWidget * parentWidget() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:49:58 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.