1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2015-01-19
7 * Description : message box notification settings
8 *
9 * Copyright (C) 2015-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "dmessagebox.h"
25
26 // Qt includes
27
28 #include <QPointer>
29 #include <QCheckBox>
30 #include <QGroupBox>
31 #include <QLayout>
32 #include <QLabel>
33 #include <QHeaderView>
34 #include <QApplication>
35 #include <QStyle>
36 #include <QUrl>
37 #include <QIcon>
38 #include <QDialog>
39 #include <QPushButton>
40 #include <QDialogButtonBox>
41
42 // KDE includes
43
44 #include <ksharedconfig.h>
45 #include <kconfiggroup.h>
46 #include <klocalizedstring.h>
47
48 namespace Digikam
49 {
50
readMsgBoxShouldBeShown(const QString & dontShowAgainName)51 bool DMessageBox::readMsgBoxShouldBeShown(const QString& dontShowAgainName)
52 {
53 if (dontShowAgainName.isEmpty())
54 {
55 return false;
56 }
57
58 KSharedConfigPtr config = KSharedConfig::openConfig();
59 KConfigGroup group = config->group("Notification Messages");
60 bool value = group.readEntry(dontShowAgainName, false);
61
62 return value;
63 }
64
saveMsgBoxShouldBeShown(const QString & dontShowAgainName,bool value)65 void DMessageBox::saveMsgBoxShouldBeShown(const QString& dontShowAgainName, bool value)
66 {
67 if (dontShowAgainName.isEmpty())
68 {
69 return;
70 }
71
72 KSharedConfigPtr config = KSharedConfig::openConfig();
73 KConfigGroup group = config->group("Notification Messages");
74
75 group.writeEntry(dontShowAgainName, value);
76 config->sync();
77 }
78
79 // --------------------------------------------------------------------------------------------------------
80
showInformationList(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,const QStringList & items,const QString & dontShowAgainName)81 void DMessageBox::showInformationList(QMessageBox::Icon icon,
82 QWidget* const parent,
83 const QString& caption,
84 const QString& text,
85 const QStringList& items,
86 const QString& dontShowAgainName)
87 {
88 showInformationWidget(icon, parent, caption, text, createWidgetList(items), dontShowAgainName);
89 }
90
showInformationWidget(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,QWidget * const listWidget,const QString & dontShowAgainName)91 void DMessageBox::showInformationWidget(QMessageBox::Icon icon,
92 QWidget* const parent,
93 const QString& caption,
94 const QString& text,
95 QWidget* const listWidget,
96 const QString& dontShowAgainName)
97 {
98 if (readMsgBoxShouldBeShown(dontShowAgainName))
99 {
100 return;
101 }
102
103 QDialog* const dialog = new QDialog(parent, Qt::Dialog);
104 dialog->setWindowTitle(caption);
105 dialog->setObjectName(QLatin1String("showInformation"));
106 dialog->setModal(true);
107
108 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok, dialog);
109 buttons->button(QDialogButtonBox::Ok)->setDefault(true);
110 buttons->button(QDialogButtonBox::Ok)->setShortcut(Qt::Key_Escape);
111
112 QObject::connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
113 dialog, SLOT(accept()));
114
115 bool checkboxResult = false;
116
117 createMessageBox(dialog, buttons, createIcon(icon), text, listWidget,
118 dontShowAgainName.isEmpty() ? QString() : i18n("Do not show this message again"),
119 &checkboxResult);
120
121 saveMsgBoxShouldBeShown(dontShowAgainName, checkboxResult);
122 }
123
124 // --------------------------------------------------------------------------------------------------------
125
showContinueCancel(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,const QString & dontAskAgainName)126 int DMessageBox::showContinueCancel(QMessageBox::Icon icon,
127 QWidget* const parent,
128 const QString& caption,
129 const QString& text,
130 const QString& dontAskAgainName)
131 {
132 return (showContinueCancelList(icon, parent, caption, text, QStringList(), dontAskAgainName));
133 }
134
showContinueCancelList(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,const QStringList & items,const QString & dontAskAgainName)135 int DMessageBox::showContinueCancelList(QMessageBox::Icon icon,
136 QWidget* const parent,
137 const QString& caption,
138 const QString& text,
139 const QStringList& items,
140 const QString& dontAskAgainName)
141 {
142 return (showContinueCancelWidget(icon, parent, caption, text, createWidgetList(items), dontAskAgainName));
143 }
144
showContinueCancelWidget(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,QWidget * const listWidget,const QString & dontAskAgainName)145 int DMessageBox::showContinueCancelWidget(QMessageBox::Icon icon,
146 QWidget* const parent,
147 const QString& caption,
148 const QString& text,
149 QWidget* const listWidget,
150 const QString& dontAskAgainName)
151 {
152 if (readMsgBoxShouldBeShown(dontAskAgainName))
153 {
154 return QMessageBox::Yes;
155 }
156
157 QDialog* const dialog = new QDialog(parent, Qt::Dialog);
158 dialog->setWindowTitle(caption);
159 dialog->setObjectName(QLatin1String("showContinueCancel"));
160 dialog->setModal(true);
161
162 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::Cancel, dialog);
163 buttons->button(QDialogButtonBox::Yes)->setDefault(true);
164 buttons->button(QDialogButtonBox::Yes)->setText(i18n("Continue"));
165 buttons->button(QDialogButtonBox::Cancel)->setShortcut(Qt::Key_Escape);
166
167 QObject::connect(buttons->button(QDialogButtonBox::Yes), SIGNAL(clicked()),
168 dialog, SLOT(accept()));
169
170 QObject::connect(buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
171 dialog, SLOT(reject()));
172
173 bool checkboxResult = false;
174 const int result = createMessageBox(dialog, buttons, createIcon(icon), text, listWidget,
175 dontAskAgainName.isEmpty() ? QString() : i18n("Do not ask again"),
176 &checkboxResult);
177
178 if (result != QDialog::Accepted)
179 {
180 return QMessageBox::Cancel;
181 }
182
183 saveMsgBoxShouldBeShown(dontAskAgainName, checkboxResult);
184
185 return QMessageBox::Yes;
186 }
187
188 // --------------------------------------------------------------------------------------------------------
189
showYesNo(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,const QString & dontAskAgainName)190 int DMessageBox::showYesNo(QMessageBox::Icon icon,
191 QWidget* const parent,
192 const QString& caption,
193 const QString& text,
194 const QString& dontAskAgainName)
195 {
196 return (showYesNoList(icon, parent, caption, text, QStringList(), dontAskAgainName));
197 }
198
showYesNoList(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,const QStringList & items,const QString & dontAskAgainName)199 int DMessageBox::showYesNoList(QMessageBox::Icon icon,
200 QWidget* const parent,
201 const QString& caption,
202 const QString& text,
203 const QStringList& items,
204 const QString& dontAskAgainName)
205 {
206 return (showYesNoWidget(icon, parent, caption, text, createWidgetList(items), dontAskAgainName));
207 }
208
showYesNoWidget(QMessageBox::Icon icon,QWidget * const parent,const QString & caption,const QString & text,QWidget * const listWidget,const QString & dontAskAgainName)209 int DMessageBox::showYesNoWidget(QMessageBox::Icon icon,
210 QWidget* const parent,
211 const QString& caption,
212 const QString& text,
213 QWidget* const listWidget,
214 const QString& dontAskAgainName)
215 {
216 if (readMsgBoxShouldBeShown(dontAskAgainName))
217 {
218 return QMessageBox::Yes;
219 }
220
221 QDialog* const dialog = new QDialog(parent, Qt::Dialog);
222 dialog->setWindowTitle(caption);
223 dialog->setObjectName(QLatin1String("showYesNo"));
224 dialog->setModal(true);
225
226 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No, dialog);
227 buttons->button(QDialogButtonBox::No)->setDefault(true);
228 buttons->button(QDialogButtonBox::No)->setShortcut(Qt::Key_Escape);
229
230 QObject::connect(buttons->button(QDialogButtonBox::Yes), &QAbstractButton::clicked,
231 dialog, [dialog]() { dialog->done(QDialogButtonBox::Yes); });
232
233 QObject::connect(buttons->button(QDialogButtonBox::No), &QAbstractButton::clicked,
234 dialog, [dialog]() { dialog->done(QDialogButtonBox::No); });
235
236 bool checkboxResult = false;
237 int result = createMessageBox(dialog, buttons, createIcon(icon), text, listWidget,
238 dontAskAgainName.isEmpty() ? QString() : i18n("Do not ask again"),
239 &checkboxResult);
240
241 if (result == QDialogButtonBox::Yes)
242 {
243 saveMsgBoxShouldBeShown(dontAskAgainName, checkboxResult);
244
245 return QMessageBox::Yes;
246 }
247 else if (result == QDialogButtonBox::No)
248 {
249 saveMsgBoxShouldBeShown(dontAskAgainName, checkboxResult);
250
251 return QMessageBox::No;
252 }
253
254 return QMessageBox::Cancel;
255 }
256
257 // --------------------------------------------------------------------------------------------------------
258
createMessageBox(QDialog * const dialog,QDialogButtonBox * const buttons,const QIcon & icon,const QString & text,QWidget * const listWidget,const QString & ask,bool * checkboxReturn)259 int DMessageBox::createMessageBox(QDialog* const dialog,
260 QDialogButtonBox* const buttons,
261 const QIcon& icon,
262 const QString& text,
263 QWidget* const listWidget,
264 const QString& ask,
265 bool* checkboxReturn)
266 {
267 const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
268
269 QWidget* const mainWidget = new QWidget(dialog);
270 QVBoxLayout* const mainLayout = new QVBoxLayout(mainWidget);
271 mainLayout->setContentsMargins(spacing, spacing, spacing, spacing);
272 mainLayout->setSpacing(spacing);
273
274 QHBoxLayout* const hLayout = new QHBoxLayout();
275 hLayout->setContentsMargins(QMargins());
276 hLayout->setSpacing(-1); // use default spacing
277 mainLayout->addLayout(hLayout, 5);
278
279 //--------------------------------------------------------------------------------
280
281 QLabel* const iconLabel = new QLabel(mainWidget);
282 QStyleOption option;
283 option.initFrom(mainWidget);
284 iconLabel->setPixmap(icon.pixmap(mainWidget->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, mainWidget)));
285
286 QVBoxLayout* const iconLayout = new QVBoxLayout();
287 iconLayout->addStretch(1);
288 iconLayout->addWidget(iconLabel);
289 iconLayout->addStretch(5);
290 hLayout->addLayout(iconLayout, 0);
291 hLayout->addSpacing(spacing);
292
293 //--------------------------------------------------------------------------------
294
295 QLabel* const messageLabel = new QLabel(text, mainWidget);
296 messageLabel->setOpenExternalLinks(true);
297 messageLabel->setWordWrap(true);
298 messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
299 QPalette messagePal(messageLabel->palette());
300 messagePal.setColor(QPalette::Window, Qt::transparent);
301 messageLabel->setPalette(messagePal);
302 hLayout->addWidget(messageLabel, 5);
303
304 //--------------------------------------------------------------------------------
305
306 if (listWidget)
307 {
308 listWidget->setParent(mainWidget);
309 mainLayout->addWidget(listWidget, 50);
310 }
311
312 //--------------------------------------------------------------------------------
313
314 QPointer<QCheckBox> checkbox = nullptr;
315
316 if (!ask.isEmpty())
317 {
318 checkbox = new QCheckBox(ask, mainWidget);
319 mainLayout->addWidget(checkbox);
320
321 if (checkboxReturn)
322 {
323 checkbox->setChecked(*checkboxReturn);
324 }
325 }
326
327 //--------------------------------------------------------------------------------
328
329 mainLayout->addWidget(buttons);
330 dialog->setLayout(mainLayout);
331
332 //--------------------------------------------------------------------------------
333
334 // We use a QPointer because the dialog may get deleted
335 // during exec() if the parent of the dialog gets deleted.
336 // In that case the QPointer will reset to 0.
337
338 QPointer<QDialog> guardedDialog = dialog;
339
340 const int result = guardedDialog->exec();
341
342 if (checkbox && checkboxReturn)
343 {
344 *checkboxReturn = checkbox->isChecked();
345 }
346
347 delete guardedDialog;
348
349 return result;
350 }
351
createIcon(QMessageBox::Icon icon)352 QIcon DMessageBox::createIcon(QMessageBox::Icon icon)
353 {
354 QIcon tmpIcon;
355
356 switch (icon)
357 {
358 case QMessageBox::Warning:
359 tmpIcon = qApp->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, qApp->activeWindow());
360 break;
361
362 case QMessageBox::Critical:
363 tmpIcon = qApp->style()->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, qApp->activeWindow());
364 break;
365
366 case QMessageBox::Question:
367 tmpIcon = qApp->style()->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, qApp->activeWindow());
368 break;
369
370 case QMessageBox::Information:
371 default:
372 tmpIcon = qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, qApp->activeWindow());
373 break;
374 }
375
376 int iconSize = qApp->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, qApp->activeWindow());
377
378 return tmpIcon.pixmap(iconSize);
379 }
380
381
createWidgetList(const QStringList & items)382 QListWidget* DMessageBox::createWidgetList(const QStringList& items)
383 {
384 QListWidget* listWidget = nullptr;
385
386 if (!items.isEmpty())
387 {
388 listWidget = new QListWidget();
389 listWidget->addItems(items);
390 }
391
392 return listWidget;
393 }
394
395 } // namespace Digikam
396