Akonadi

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

KDE's Doxygen guidelines are available online.