1 /* KStars Asynchronous Message Box Implementation for Desktop/Android and EkosLive
2 Based on QMessageBox.
3
4 SPDX-FileCopyrightText: 2019 Jasem Mutlaq <mutlaqja@ikarustech.com>
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "ksmessagebox.h"
10 #include "config-kstars.h"
11 #include "Options.h"
12
13 #ifdef KSTARS_LITE
14 #include "kstarslite.h"
15 #else
16 #include "kstars.h"
17 #endif
18
19 #include <QPushButton>
20 #include <QCheckBox>
21 #include <QLayout>
22 #include <QSpacerItem>
23 #include <QLabel>
24
25 KSMessageBox * KSMessageBox::m_Instance = nullptr;
26
Instance()27 KSMessageBox * KSMessageBox::Instance()
28 {
29 if (!m_Instance)
30 m_Instance = new KSMessageBox();
31
32 return m_Instance;
33 }
34
KSMessageBox()35 KSMessageBox::KSMessageBox() : QMessageBox()
36 {
37 setDefaultButton(StandardButton::Ok);
38 setIcon(QMessageBox::Information);
39 setObjectName("KSMessageBox");
40
41 setWindowFlags(Qt::WindowStaysOnTopHint);
42
43 m_ProgressTimer.setInterval(1000);
44 m_ProgressTimer.setSingleShot(false);
45 connect(&m_ProgressTimer, &QTimer::timeout, this, &KSMessageBox::timerTick);
46
47 connect(this, &KSMessageBox::rejected, [this]()
48 {
49 m_ProgressTimer.stop();
50 emit newMessage(QJsonObject());
51 });
52
53 connect(this, &KSMessageBox::accepted, [this]()
54 {
55 m_ProgressTimer.stop();
56 emit newMessage(QJsonObject());
57 });
58 }
59
error(const QString & message,const QString & title,quint32 timeout)60 void KSMessageBox::error(const QString &message, const QString &title, quint32 timeout)
61 {
62 #ifdef KSTARS_LITE
63 Q_UNUSED(title);
64 KStarsLite::Instance()->notificationMessage(message);
65 #else
66 //KMessageBox::error(nullptr, message, title);
67 reset();
68
69 addOKButton();
70 setIcon(QMessageBox::Critical);
71 setText(message);
72 setWindowTitle(title);
73
74 setupTimeout(timeout);
75 open();
76
77 emit newMessage(createMessageObject());
78 #endif
79 }
80
sorry(const QString & message,const QString & title,quint32 timeout)81 void KSMessageBox::sorry(const QString &message, const QString &title, quint32 timeout)
82 {
83 #ifdef KSTARS_LITE
84 Q_UNUSED(title);
85 KStarsLite::Instance()->notificationMessage(message);
86 #else
87 //KSNotification::sorry(message, title);
88 reset();
89
90 addOKButton();
91 setIcon(QMessageBox::Warning);
92 setText(message);
93 setWindowTitle(title);
94
95 setupTimeout(timeout);
96 open();
97
98 emit newMessage(createMessageObject());
99 #endif
100 }
101
info(const QString & message,const QString & title,quint32 timeout)102 void KSMessageBox::info(const QString &message, const QString &title, quint32 timeout)
103 {
104 #ifdef KSTARS_LITE
105 Q_UNUSED(title);
106 KStarsLite::Instance()->notificationMessage(message);
107 #else
108 //KMessageBox::information(nullptr, message, title);
109 reset();
110
111 addOKButton();
112 setIcon(QMessageBox::Information);
113 setText(message);
114 setWindowTitle(title);
115
116 setupTimeout(timeout);
117 open();
118
119 emit newMessage(createMessageObject());
120
121
122 #endif
123 }
124
setupTimeout(quint32 timeout)125 void KSMessageBox::setupTimeout(quint32 timeout)
126 {
127 m_Timeout = timeout;
128 if (m_Timeout == 0)
129 return;
130
131 m_ProgressLabel = new QLabel(this);
132 m_ProgressLabel->setText(i18n("Auto close in ..."));
133
134 m_ProgressIndicator = new QRoundProgressBar(this);
135 m_ProgressIndicator->setDecimals(0);
136 m_ProgressIndicator->setFormat("%v");
137 m_ProgressIndicator->setBarStyle(QRoundProgressBar::StyleLine);
138 m_ProgressIndicator->setFixedSize(QSize(32, 32));
139
140 m_ProgressLayout = new QHBoxLayout();
141 m_ProgressLayout->setObjectName("ProgressLayout");
142 m_ProgressLayout->addWidget(m_ProgressLabel);
143 m_ProgressLayout->addWidget(m_ProgressIndicator);
144
145 QGridLayout *gridLayout = qobject_cast<QGridLayout*>(layout());
146 if (gridLayout)
147 {
148 //gridLayout->addWidget(m_ProgressLabel.get(), 1, 2, 1, 1, Qt::AlignHCenter | Qt::AlignVCenter);
149 //gridLayout->addWidget(m_ProgressIndicator.get(), 1, 2, 1, 1, Qt::AlignHCenter | Qt::AlignVCenter);
150 gridLayout->addItem(m_ProgressLayout, 1, 2, 1, 2, Qt::AlignHCenter | Qt::AlignVCenter);
151 }
152
153 m_ProgressTimer.start();
154 m_ProgressIndicator->setRange(0, m_Timeout);
155 m_ProgressIndicator->setValue(static_cast<int>(m_Timeout));
156 }
157
reset()158 void KSMessageBox::reset()
159 {
160 m_ProgressTimer.stop();
161 resetTimeout();
162
163 QList<QPushButton *> allButtons = findChildren<QPushButton*>();
164 qDeleteAll(allButtons);
165
166 delete (m_ProgressIndicator);
167 delete (m_ProgressLabel);
168 if (m_ProgressLayout)
169 {
170 layout()->removeItem(m_ProgressLayout);
171 delete (m_ProgressLayout);
172 }
173
174 }
175
questionYesNo(const QString & message,const QString & title,quint32 timeout,bool defaultToYes,const QString & yesText,const QString & noText)176 void KSMessageBox::questionYesNo(const QString &message, const QString &title, quint32 timeout, bool defaultToYes,
177 const QString &yesText, const QString &noText)
178 {
179 reset();
180
181 setIcon(QMessageBox::Question);
182 setText(message);
183 setWindowTitle(title);
184
185 QPushButton *yesButton = new QPushButton(yesText, this);
186 QPushButton *noButton = new QPushButton(noText, this);
187
188 connect(yesButton, &QPushButton::clicked, this, &KSMessageBox::accepted);
189 connect(noButton, &QPushButton::clicked, this, &KSMessageBox::rejected);
190
191 addButton(yesButton, QMessageBox::ActionRole);
192 addButton(noButton, QMessageBox::ActionRole);
193
194
195 setDefaultButton(defaultToYes ? yesButton : noButton);
196 yesButton->setDefault(defaultToYes);
197 noButton->setDefault(!defaultToYes);
198
199 setupTimeout(timeout);
200
201 open();
202
203 emit newMessage(createMessageObject());
204 }
205
warningContinueCancel(const QString & message,const QString & title,quint32 timeout,bool defaultToContinue,const QString & continueText,const QString & cancelText)206 void KSMessageBox::warningContinueCancel(const QString &message, const QString &title, quint32 timeout,
207 bool defaultToContinue,
208 const QString &continueText, const QString &cancelText)
209 {
210 reset();
211
212 setIcon(QMessageBox::Warning);
213 setText(message);
214 setWindowTitle(title);
215
216 QPushButton *continueButton = new QPushButton(continueText, this);
217 QPushButton *cancelButton = new QPushButton(cancelText, this);
218
219 connect(continueButton, &QPushButton::clicked, this, &KSMessageBox::accepted);
220 connect(cancelButton, &QPushButton::clicked, this, &KSMessageBox::rejected);
221
222 addButton(continueButton, QMessageBox::ActionRole);
223 addButton(cancelButton, QMessageBox::ActionRole);
224
225 setDefaultButton(defaultToContinue ? continueButton : cancelButton);
226 continueButton->setDefault(defaultToContinue);
227 cancelButton->setDefault(!defaultToContinue);
228
229 setupTimeout(timeout);
230
231 open();
232
233 emit newMessage(createMessageObject());
234 }
235
transient(const QString & message,const QString & title)236 void KSMessageBox::transient(const QString &message, const QString &title)
237 {
238 #ifdef KSTARS_LITE
239 Q_UNUSED(title);
240 KStarsLite::Instance()->notificationMessage(message);
241 #else
242 QPointer<QMessageBox> msgBox = new QMessageBox();
243 msgBox->setAttribute(Qt::WA_DeleteOnClose);
244 msgBox->setWindowTitle(title);
245 msgBox->setText(message);
246 msgBox->setModal(false);
247 msgBox->setIcon(QMessageBox::Warning);
248 msgBox->show();
249 #endif
250 }
251
addOKButton()252 void KSMessageBox::addOKButton()
253 {
254 QPushButton *okButton = new QPushButton(i18n("Ok"), this);
255 connect(okButton, &QPushButton::clicked, this, &KSMessageBox::accepted);
256 addButton(okButton, QMessageBox::AcceptRole);
257 setDefaultButton(okButton);
258 }
259
timerTick()260 void KSMessageBox::timerTick()
261 {
262 m_Timeout--;
263 m_ProgressIndicator->setValue(static_cast<int>(m_Timeout));
264
265 if (m_Timeout == 0)
266 {
267 m_ProgressTimer.stop();
268 if (defaultButton())
269 defaultButton()->animateClick();
270 else
271 reject();
272 }
273 }
274
createMessageObject()275 QJsonObject KSMessageBox::createMessageObject()
276 {
277 QJsonObject message;
278 QJsonArray buttons;
279
280 message.insert("title", windowTitle());
281 message.insert("message", text());
282 message.insert("icon", icon());
283 message.insert("timeout", static_cast<int32_t>(m_Timeout));
284
285 for (const auto oneButton : findChildren<QPushButton*>())
286 {
287 buttons.append(oneButton->text());
288 if (oneButton == defaultButton())
289 message.insert("default", oneButton->text());
290 }
291
292 message.insert("buttons", buttons);
293
294 return message;
295 }
296
selectResponse(const QString & button)297 bool KSMessageBox::selectResponse(const QString &button)
298 {
299 for (const auto oneButton : findChildren<QPushButton*>())
300 {
301 const QString buttonText = oneButton->text().remove("&");
302
303 if (button == buttonText)
304 {
305 oneButton->animateClick();
306 return true;
307 }
308 }
309
310 return false;
311 }
312