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:
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(QIcon::fromTheme(QStringLiteral("akonadi")).pixmap(64));
85 ui->brokenIcon->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-error")).pixmap(64));
86 ui->progressIcon->setPixmap(QIcon::fromTheme(QStringLiteral("akonadi")).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
98 const ServerManager::State state = ServerManager::state();
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{
166 const ServerManager::State state = ServerManager::state();
167 if (state == ServerManager::Running) {
168 serverStateChanged(state);
169 } else {
170 ServerManager::start();
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) {
217 case ServerManager::NotRunning:
218 ui->stackWidget->setCurrentWidget(ui->notRunningPage);
219 break;
220 case ServerManager::Broken:
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;
227 case ServerManager::Starting:
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;
232 case ServerManager::Stopping:
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;
237 case ServerManager::Upgrading:
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;
245 case ServerManager::Running:
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.
State
Enum for the various states the server can be in.
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-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:51:45 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.