1 | /* |
2 | Copyright (c) 2008 Volker Krause <vkrause@kde.org> |
3 | |
4 | This library is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU Library General Public License as published by |
6 | the Free Software Foundation; either version 2 of the License, or (at your |
7 | option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, but WITHOUT |
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
12 | License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to the |
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
17 | 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "erroroverlay_p.h" |
21 | #include "ui_erroroverlay.h" |
22 | #include "selftestdialog_p.h" |
23 | |
24 | #include <KDebug> |
25 | #include <KIcon> |
26 | #include <KLocalizedString> |
27 | |
28 | #include <QtCore/QEvent> |
29 | #include <QPalette> |
30 | |
31 | using namespace Akonadi; |
32 | |
33 | //@cond PRIVATE |
34 | |
35 | class ErrorOverlayStatic |
36 | { |
37 | public: |
38 | QVector<QPair<QPointer<QWidget>, QPointer<QWidget> > > baseWidgets; |
39 | }; |
40 | |
41 | K_GLOBAL_STATIC(ErrorOverlayStatic, sInstanceOverlay) |
42 | |
43 | static bool isParentOf(QObject *o1, QObject *o2) |
44 | { |
45 | if (!o1 || !o2) { |
46 | return false; |
47 | } |
48 | if (o1 == o2) { |
49 | return true; |
50 | } |
51 | return isParentOf(o1, o2->parent()); |
52 | } |
53 | |
54 | ErrorOverlay::ErrorOverlay(QWidget *baseWidget, QWidget *parent) |
55 | : QWidget(parent ? parent : baseWidget->window()) |
56 | , mBaseWidget(baseWidget) |
57 | , mOverlayActive(false) |
58 | , mBaseWidgetIsParent(false) |
59 | , ui(new Ui::ErrorOverlay) |
60 | { |
61 | Q_ASSERT(baseWidget); |
62 | |
63 | mBaseWidgetIsParent = isParentOf(mBaseWidget, this); |
64 | |
65 | // check existing overlays to detect cascading |
66 | for (QVector<QPair< QPointer<QWidget>, QPointer<QWidget> > >::Iterator it = sInstanceOverlay->baseWidgets.begin(); |
67 | it != sInstanceOverlay->baseWidgets.end();) { |
68 | if ((*it).first == 0 || (*it).second == 0) { |
69 | // garbage collection |
70 | it = sInstanceOverlay->baseWidgets.erase(it); |
71 | continue; |
72 | } |
73 | if (isParentOf((*it).first, baseWidget)) { |
74 | // parent already has an overlay, kill ourselves |
75 | mBaseWidget = 0; |
76 | hide(); |
77 | deleteLater(); |
78 | return; |
79 | } |
80 | if (isParentOf(baseWidget, (*it).first)) { |
81 | // child already has overlay, kill that one |
82 | delete(*it).second; |
83 | it = sInstanceOverlay->baseWidgets.erase(it); |
84 | continue; |
85 | } |
86 | ++it; |
87 | } |
88 | sInstanceOverlay->baseWidgets.append(qMakePair(mBaseWidget, QPointer<QWidget>(this))); |
89 | |
90 | connect(baseWidget, SIGNAL(destroyed()), SLOT(deleteLater())); |
91 | mPreviousState = mBaseWidget->isEnabled(); |
92 | |
93 | ui->setupUi(this); |
94 | ui->notRunningIcon->setPixmap(KIcon(QLatin1String("akonadi" )).pixmap(64)); |
95 | ui->brokenIcon->setPixmap(KIcon(QString::fromLatin1("dialog-error" )).pixmap(64)); |
96 | ui->progressIcon->setPixmap(KIcon(QLatin1String("akonadi" )).pixmap(32)); |
97 | ui->quitButton->setText(KStandardGuiItem::quit().text()); |
98 | ui->detailsQuitButton->setText(KStandardGuiItem::quit().text()); |
99 | |
100 | #ifndef KDEPIM_MOBILE_UI |
101 | ui->quitButton->hide(); |
102 | ui->detailsQuitButton->hide(); |
103 | #endif |
104 | |
105 | connect(ui->startButton, SIGNAL(clicked()), SLOT(startClicked())); |
106 | connect(ui->quitButton, SIGNAL(clicked()), SLOT(quitClicked())); |
107 | connect(ui->detailsQuitButton, SIGNAL(clicked()), SLOT(quitClicked())); |
108 | connect(ui->selfTestButton, SIGNAL(clicked()), SLOT(selfTestClicked())); |
109 | |
110 | const ServerManager::State state = ServerManager::state(); |
111 | mOverlayActive = (state == ServerManager::Running); |
112 | serverStateChanged(state); |
113 | |
114 | connect(ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), |
115 | SLOT(serverStateChanged(Akonadi::ServerManager::State))); |
116 | |
117 | QPalette p = palette(); |
118 | p.setColor(backgroundRole(), QColor(0, 0, 0, 128)); |
119 | p.setColor(foregroundRole(), Qt::white); |
120 | setPalette(p); |
121 | setAutoFillBackground(true); |
122 | |
123 | mBaseWidget->installEventFilter(this); |
124 | |
125 | reposition(); |
126 | } |
127 | |
128 | ErrorOverlay::~ ErrorOverlay() |
129 | { |
130 | if (mBaseWidget && !mBaseWidgetIsParent) { |
131 | mBaseWidget->setEnabled(mPreviousState); |
132 | } |
133 | } |
134 | |
135 | void ErrorOverlay::reposition() |
136 | { |
137 | if (!mBaseWidget) { |
138 | return; |
139 | } |
140 | |
141 | // reparent to the current top level widget of the base widget if needed |
142 | // needed eg. in dock widgets |
143 | if (parentWidget() != mBaseWidget->window()) { |
144 | setParent(mBaseWidget->window()); |
145 | } |
146 | |
147 | // follow base widget visibility |
148 | // needed eg. in tab widgets |
149 | if (!mBaseWidget->isVisible()) { |
150 | hide(); |
151 | return; |
152 | } |
153 | if (mOverlayActive) { |
154 | show(); |
155 | } |
156 | |
157 | // follow position changes |
158 | const QPoint topLevelPos = mBaseWidget->mapTo(window(), QPoint(0, 0)); |
159 | const QPoint parentPos = parentWidget()->mapFrom(window(), topLevelPos); |
160 | move(parentPos); |
161 | |
162 | // follow size changes |
163 | // TODO: hide/scale icon if we don't have enough space |
164 | resize(mBaseWidget->size()); |
165 | } |
166 | |
167 | bool ErrorOverlay::eventFilter(QObject *object, QEvent *event) |
168 | { |
169 | if (object == mBaseWidget && mOverlayActive && |
170 | (event->type() == QEvent::Move || event->type() == QEvent::Resize || |
171 | event->type() == QEvent::Show || event->type() == QEvent::Hide || |
172 | event->type() == QEvent::ParentChange)) { |
173 | reposition(); |
174 | } |
175 | return QWidget::eventFilter(object, event); |
176 | } |
177 | |
178 | void ErrorOverlay::startClicked() |
179 | { |
180 | const ServerManager::State state = ServerManager::state(); |
181 | if (state == ServerManager::Running) { |
182 | serverStateChanged(state); |
183 | } else { |
184 | ServerManager::start(); |
185 | } |
186 | } |
187 | |
188 | void ErrorOverlay::quitClicked() |
189 | { |
190 | qApp->quit(); |
191 | } |
192 | |
193 | void ErrorOverlay::selfTestClicked() |
194 | { |
195 | SelfTestDialog dlg; |
196 | dlg.exec(); |
197 | } |
198 | |
199 | void ErrorOverlay::serverStateChanged(ServerManager::State state) |
200 | { |
201 | if (!mBaseWidget) { |
202 | return; |
203 | } |
204 | |
205 | if (state == ServerManager::Running && mOverlayActive) { |
206 | mOverlayActive = false; |
207 | hide(); |
208 | if (!mBaseWidgetIsParent) { |
209 | mBaseWidget->setEnabled(mPreviousState); |
210 | } |
211 | } else if (!mOverlayActive) { |
212 | mOverlayActive = true; |
213 | if (mBaseWidget->isVisible()) { |
214 | show(); |
215 | } |
216 | |
217 | if (!mBaseWidgetIsParent) { |
218 | mPreviousState = mBaseWidget->isEnabled(); |
219 | mBaseWidget->setEnabled(false); |
220 | } |
221 | |
222 | reposition(); |
223 | } |
224 | |
225 | if (mOverlayActive) { |
226 | switch (state) { |
227 | case ServerManager::NotRunning: |
228 | ui->stackWidget->setCurrentWidget(ui->notRunningPage); |
229 | break; |
230 | case ServerManager::Broken: |
231 | ui->stackWidget->setCurrentWidget(ui->brokenPage); |
232 | break; |
233 | case ServerManager::Starting: |
234 | ui->progressPage->setToolTip(i18n("Personal information management service is starting..." )); |
235 | ui->progressDescription->setText(i18n("Personal information management service is starting..." )); |
236 | ui->stackWidget->setCurrentWidget(ui->progressPage); |
237 | break; |
238 | case ServerManager::Stopping: |
239 | ui->progressPage->setToolTip(i18n("Personal information management service is shutting down..." )); |
240 | ui->progressDescription->setText(i18n("Personal information management service is shutting down..." )); |
241 | ui->stackWidget->setCurrentWidget(ui->progressPage); |
242 | break; |
243 | case ServerManager::Upgrading: |
244 | ui->progressPage->setToolTip(i18n("Personal information management service is performing a database upgrade." )); |
245 | ui->progressDescription->setText(i18n("Personal information management service is performing a database upgrade.\n" |
246 | "This happens after a software update and is necessary to optimize performance.\n" |
247 | "Depending on the amount of personal information, this might take a few minutes." )); |
248 | ui->stackWidget->setCurrentWidget(ui->progressPage); |
249 | break; |
250 | case ServerManager::Running: |
251 | break; |
252 | } |
253 | } |
254 | } |
255 | |
256 | //@endcond |
257 | |
258 | #include "moc_erroroverlay_p.cpp" |
259 | |