1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 Waldo Bastian <bastian@kde.org>
4 SPDX-FileCopyrightText: 2012 David Faure <faure+bluesystems@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "kmessagebox.h"
10#include "kmessagebox_p.h"
11
12#include <QCheckBox>
13#include <QDialog>
14#include <QLabel>
15#include <QLayout>
16#include <QListWidget>
17#include <QPointer>
18#include <QPushButton>
19#include <QScreen>
20#include <QScrollArea>
21#include <QScrollBar>
22#include <QTextBrowser>
23#include <QWindow>
24
25#include <qapplication.h>
26#if 0
27// NOTE waiting for the notification framework plan
28#include <knotification.h>
29#endif
30#include <ksqueezedtextlabel.h>
31
32#include <KCollapsibleGroupBox>
33
34namespace KMessageBox
35{
36/**
37 * @private Prevent kapidox's doxygen config to pick up this namespace variable
38 * this static is used by the createKMessageBox function to enqueue dialogs
39 * FIXME what should we do about this static?
40 */
41QDialogButtonBox::StandardButton KWIDGETSADDONS_EXPORT (*KMessageBox_exec_hook)(QDialog *) = nullptr;
42
43/// @private Prevent kapidox's doxygen config pick up this namespace method
44static void applyOptions(QDialog *dialog, KMessageBox::Options options)
45{
46 if (options & KMessageBox::WindowModal) {
47 dialog->setWindowModality(Qt::WindowModal);
48 }
49 dialog->setModal(true);
50}
51
52/// @private Prevent kapidox's doxygen config pick up this namespace method
53// This method has been copied from KWindowSystem to avoid depending on it
54static void setMainWindow(QWidget *subWidget, WId mainWindowId)
55{
56#ifdef Q_OS_OSX
57 if (!QWidget::find(mainWindowId)) {
58 return;
59 }
60#endif
61 // Set the WA_NativeWindow attribute to force the creation of the QWindow.
62 // Without this QWidget::windowHandle() returns 0.
63 subWidget->setAttribute(Qt::WA_NativeWindow, on: true);
64 QWindow *subWindow = subWidget->windowHandle();
65 Q_ASSERT(subWindow);
66
67 QWindow *mainWindow = QWindow::fromWinId(id: mainWindowId);
68 if (!mainWindow) {
69 // foreign windows not supported on all platforms
70 return;
71 }
72 // mainWindow is not the child of any object, so make sure it gets deleted at some point
73 QObject::connect(sender: subWidget, signal: &QObject::destroyed, context: mainWindow, slot: &QObject::deleteLater);
74 subWindow->setTransientParent(mainWindow);
75}
76
77/**
78 * @private Prevent kapidox's doxygen config pick up this namespace method
79 * Create a QDialog whose parent is a foreign window
80 */
81static QDialog *createWIdDialog(WId parent_id)
82{
83 QWidget *parent = QWidget::find(parent_id);
84 QDialog *dialog = new QDialog(parent, Qt::Dialog);
85 if (!parent && parent_id) {
86 setMainWindow(subWidget: dialog, mainWindowId: parent_id);
87 }
88 return dialog;
89}
90
91class DialogButtonsHelper : public QObject
92{
93 Q_OBJECT
94public:
95 DialogButtonsHelper(QDialog *dialog, QDialogButtonBox *buttons)
96 : QObject(dialog)
97 , m_dialog(dialog)
98 , m_buttons(buttons)
99 , m_details(nullptr)
100 {
101 connect(sender: m_buttons, signal: &QDialogButtonBox::clicked, context: this, slot: &DialogButtonsHelper::onButtonClicked);
102 }
103
104 void setDetailsWidget(QWidget *widget)
105 {
106 m_details = widget;
107 }
108
109public Q_SLOTS:
110 void onButtonClicked(QAbstractButton *button)
111 {
112 QDialogButtonBox::StandardButton code = m_buttons->standardButton(button);
113 if (code != QDialogButtonBox::NoButton) {
114 m_dialog->done(code);
115 }
116 }
117
118private:
119 QDialog *const m_dialog;
120 QDialogButtonBox *const m_buttons;
121 QWidget *m_details;
122};
123
124QDialogButtonBox::StandardButton createKMessageBox(QDialog *dialog,
125 QDialogButtonBox *buttons,
126 QMessageBox::Icon icon,
127 const QString &text,
128 const QStringList &strlist,
129 const QString &ask,
130 bool *checkboxReturn,
131 Options options,
132 const QString &details)
133{
134 QIcon tmpIcon;
135 QStyle *style = dialog ? dialog->style() : QApplication::style();
136 switch (icon) {
137 case QMessageBox::Information:
138 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxInformation, option: nullptr, widget: dialog);
139 break;
140 case QMessageBox::Warning:
141 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxWarning, option: nullptr, widget: dialog);
142 break;
143 case QMessageBox::Critical:
144 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxCritical, option: nullptr, widget: dialog);
145 break;
146 case QMessageBox::Question:
147 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxQuestion, option: nullptr, widget: dialog);
148 break;
149 default:
150 break;
151 }
152
153 return createKMessageBox(dialog, buttons, icon: tmpIcon, text, strlist, ask, checkboxReturn, options, details, notifyType: icon);
154}
155
156QDialogButtonBox::StandardButton createKMessageBox(QDialog *dialog,
157 QDialogButtonBox *buttons,
158 const QIcon &icon,
159 const QString &text,
160 const QStringList &strlist,
161 const QString &ask,
162 bool *checkboxReturn,
163 Options options,
164 const QString &details,
165 QMessageBox::Icon notifyType)
166{
167 if (!isNotifyInterfaceLoaded()) {
168 // This is annoying. Loading the interface later (or at any point) will
169 // install the qm translation of the knotifications library which will cause a LanguageChange event to be sent
170 // Which will end up in QDialogButtonBoxPrivate::retranslateStrings and will overwrite the texts
171 // we have just set. So here we save our texts, force load the interface and reset the texts
172 // For people wondering if they can remove this bit of code later, this seems to only be an issue
173 // in non Plasma desktops, emulate by running something like XDG_CURRENT_DESKTOP=X-Cinnamon okular
174 // on plasma desktops the platform plugin already uses knotifications so it's qm has been loaded on startup
175 QMap<QPointer<QAbstractButton>, QString> buttonTexts;
176 for (QAbstractButton *b : buttons->buttons()) {
177 buttonTexts[b] = b->text();
178 }
179 notifyInterface();
180 QApplication::processEvents(); // We need to force the LanguageChange to be processed
181 for (auto it = buttonTexts.constBegin(); it != buttonTexts.constEnd(); ++it) {
182 if (it.key()) {
183 it.key()->setText(it.value());
184 }
185 }
186 }
187
188 DialogButtonsHelper *buttonsHelper = new DialogButtonsHelper(dialog, buttons);
189
190 QWidget *mainWidget = new QWidget(dialog);
191 QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget);
192 const int verticalSpacing = mainWidget->style()->pixelMetric(metric: QStyle::PM_LayoutVerticalSpacing);
193 const int horizontalSpacing = mainWidget->style()->pixelMetric(metric: QStyle::PM_LayoutHorizontalSpacing);
194 mainLayout->setSpacing(verticalSpacing * 2); // provide extra spacing
195 mainLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
196 buttons->setParent(dialog);
197
198 QHBoxLayout *hLayout = new QHBoxLayout();
199 hLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
200 hLayout->setSpacing(-1); // use default spacing
201 mainLayout->addLayout(layout: hLayout, stretch: 5);
202
203 QLabel *iconLabel = new QLabel(mainWidget);
204
205 if (!icon.isNull()) {
206 QStyleOption option;
207 option.initFrom(w: mainWidget);
208 iconLabel->setPixmap(icon.pixmap(extent: mainWidget->style()->pixelMetric(metric: QStyle::PM_MessageBoxIconSize, option: &option, widget: mainWidget)));
209 }
210
211 QVBoxLayout *iconLayout = new QVBoxLayout();
212 iconLayout->addStretch(stretch: 1);
213 iconLayout->addWidget(iconLabel);
214 iconLayout->addStretch(stretch: 5);
215
216 hLayout->addLayout(layout: iconLayout, stretch: 0);
217 hLayout->addSpacing(size: horizontalSpacing);
218
219 QLabel *messageLabel = new QLabel(text, mainWidget);
220 messageLabel->setOpenExternalLinks(options & KMessageBox::AllowLink);
221 Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse;
222 if (options & KMessageBox::AllowLink) {
223 flags |= Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard;
224 }
225 messageLabel->setTextInteractionFlags(flags);
226
227 QRect desktop = dialog->screen()->geometry();
228 bool usingSqueezedTextLabel = false;
229 if (messageLabel->sizeHint().width() > desktop.width() * 0.5) {
230 // enable automatic wrapping of messages which are longer than 50% of screen width
231 messageLabel->setWordWrap(true);
232 // use a squeezed label if text is still too wide
233 usingSqueezedTextLabel = messageLabel->sizeHint().width() > desktop.width() * 0.85;
234 if (usingSqueezedTextLabel) {
235 delete messageLabel;
236 messageLabel = new KSqueezedTextLabel(text, mainWidget);
237 messageLabel->setOpenExternalLinks(options & KMessageBox::AllowLink);
238 messageLabel->setTextInteractionFlags(flags);
239 }
240 }
241
242 QPalette messagePal(messageLabel->palette());
243 messagePal.setColor(acr: QPalette::Window, acolor: Qt::transparent);
244 messageLabel->setPalette(messagePal);
245
246 bool usingScrollArea = desktop.height() / 3 < messageLabel->sizeHint().height();
247 if (usingScrollArea) {
248 QScrollArea *messageScrollArea = new QScrollArea(mainWidget);
249 messageScrollArea->setWidget(messageLabel);
250 messageScrollArea->setFrameShape(QFrame::NoFrame);
251 messageScrollArea->setWidgetResizable(true);
252 QPalette scrollPal(messageScrollArea->palette());
253 scrollPal.setColor(acr: QPalette::Window, acolor: Qt::transparent);
254 messageScrollArea->viewport()->setPalette(scrollPal);
255 hLayout->addWidget(messageScrollArea, stretch: 5);
256 } else {
257 hLayout->addWidget(messageLabel, stretch: 5);
258 }
259
260 const bool usingListWidget = !strlist.isEmpty();
261 if (usingListWidget) {
262 // enable automatic wrapping since the listwidget has already a good initial width
263 messageLabel->setWordWrap(true);
264 QListWidget *listWidget = new QListWidget(mainWidget);
265 listWidget->addItems(labels: strlist);
266
267 QStyleOptionViewItem styleOption;
268 styleOption.initFrom(w: listWidget);
269 QFontMetrics fm(styleOption.font);
270 int w = listWidget->width();
271 for (const QString &str : strlist) {
272 w = qMax(a: w, b: fm.boundingRect(text: str).width());
273 }
274 const int borderWidth = listWidget->width() - listWidget->viewport()->width() + listWidget->verticalScrollBar()->height();
275 w += borderWidth;
276 if (w > desktop.width() * 0.85) { // limit listWidget size to 85% of screen width
277 w = qRound(d: desktop.width() * 0.85);
278 }
279 listWidget->setMinimumWidth(w);
280
281 mainLayout->addWidget(listWidget, stretch: usingScrollArea ? 10 : 50);
282 listWidget->setSelectionMode(QListWidget::NoSelection);
283 messageLabel->setSizePolicy(hor: QSizePolicy::Preferred, ver: QSizePolicy::Minimum);
284 } else if (!usingScrollArea) {
285 mainLayout->addStretch(stretch: 15);
286 }
287
288 QPointer<QCheckBox> checkbox = nullptr;
289 if (!ask.isEmpty()) {
290 checkbox = new QCheckBox(ask, mainWidget);
291 mainLayout->addWidget(checkbox);
292 if (checkboxReturn) {
293 checkbox->setChecked(*checkboxReturn);
294 }
295 }
296
297 QVBoxLayout *topLayout = new QVBoxLayout(dialog);
298 topLayout->addWidget(mainWidget);
299
300 if (!details.isEmpty()) {
301 QHBoxLayout *detailsHLayout = new QHBoxLayout();
302 detailsHLayout->addSpacing(size: 2 * horizontalSpacing + iconLayout->sizeHint().width());
303 KCollapsibleGroupBox *detailsGroup = new KCollapsibleGroupBox();
304 detailsGroup->setTitle(QApplication::translate(context: "KMessageBox", key: "Details"));
305 QVBoxLayout *detailsLayout = new QVBoxLayout(detailsGroup);
306 if (details.length() < 512) {
307 QLabel *detailsLabel = new QLabel(details);
308 detailsLabel->setOpenExternalLinks(options & KMessageBox::AllowLink);
309 Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse;
310 if (options & KMessageBox::AllowLink) {
311 flags |= Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard;
312 };
313 detailsLabel->setTextInteractionFlags(flags);
314 detailsLabel->setWordWrap(true);
315 detailsLabel->setMinimumSize(detailsLabel->sizeHint());
316 detailsLayout->addWidget(detailsLabel, stretch: 50);
317 } else {
318 QTextBrowser *detailTextEdit = new QTextBrowser();
319 detailTextEdit->setText(details);
320 detailTextEdit->setReadOnly(true);
321 detailTextEdit->setMinimumHeight(detailTextEdit->fontMetrics().lineSpacing() * 11);
322 detailsLayout->addWidget(detailTextEdit, stretch: 50);
323 }
324 if (!usingListWidget) {
325 mainLayout->setStretchFactor(l: hLayout, stretch: 10);
326 }
327 detailsHLayout->addWidget(detailsGroup);
328 topLayout->addLayout(layout: detailsHLayout);
329 buttonsHelper->setDetailsWidget(detailsGroup);
330 }
331
332 topLayout->addWidget(buttons);
333 topLayout->setSizeConstraint(QLayout::SetFixedSize);
334
335 if (!usingListWidget && !usingScrollArea && !usingSqueezedTextLabel && details.isEmpty()) {
336 dialog->setFixedSize(dialog->sizeHint() + QSize(10, 10));
337 }
338
339 if ((options & KMessageBox::Dangerous)) {
340 QPushButton *cancelButton = buttons->button(which: QDialogButtonBox::Cancel);
341 QPushButton *noButton = buttons->button(which: QDialogButtonBox::No);
342
343 if (cancelButton && cancelButton->isEnabled()) {
344 cancelButton->setDefault(true);
345 cancelButton->setFocus();
346 } else if (noButton && noButton->isEnabled()) {
347 noButton->setDefault(true);
348 noButton->setFocus();
349 }
350 }
351
352#ifndef Q_OS_WIN // FIXME problems with KNotify on Windows
353 if ((options & KMessageBox::Notify)) {
354 QString message = text;
355 if (!strlist.isEmpty()) {
356 message += QLatin1Char('\n') + strlist.join(sep: QLatin1Char('\n'));
357 }
358 notifyInterface()->sendNotification(notificationType: notifyType, message, parent: dialog->topLevelWidget());
359 }
360#endif
361
362 if (KMessageBox_exec_hook) {
363 return KMessageBox_exec_hook(dialog);
364 }
365
366 if ((options & KMessageBox::NoExec)) {
367 return QDialogButtonBox::NoButton; // We have to return something.
368 }
369
370 // We use a QPointer because the dialog may get deleted
371 // during exec() if the parent of the dialog gets deleted.
372 // In that case the QPointer will reset to 0.
373 QPointer<QDialog> guardedDialog = dialog;
374
375 const QDialogButtonBox::StandardButton result = QDialogButtonBox::StandardButton(guardedDialog->exec());
376 if (checkbox && checkboxReturn) {
377 *checkboxReturn = checkbox->isChecked();
378 }
379
380 delete guardedDialog;
381 return result;
382}
383
384ButtonCode questionTwoActions(QWidget *parent,
385 const QString &text,
386 const QString &title,
387 const KGuiItem &primaryAction,
388 const KGuiItem &secondaryAction,
389 const QString &dontAskAgainName,
390 Options options)
391{
392 return questionTwoActionsList(parent, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
393}
394
395bool shouldBeShownTwoActions(const QString &dontShowAgainName, ButtonCode &result)
396{
397 if (dontShowAgainName.isEmpty()) {
398 return true;
399 }
400 return dontAskAgainInterface()->shouldBeShownTwoActions(dontShowAgainName, result);
401}
402
403bool shouldBeShownContinue(const QString &dontShowAgainName)
404{
405 if (dontShowAgainName.isEmpty()) {
406 return true;
407 }
408 return dontAskAgainInterface()->shouldBeShownContinue(dontShowAgainName);
409}
410
411void saveDontShowAgainTwoActions(const QString &dontShowAgainName, ButtonCode result)
412{
413 if (dontShowAgainName.isEmpty()) {
414 return;
415 }
416 dontAskAgainInterface()->saveDontShowAgainTwoActions(dontShowAgainName, result);
417}
418
419void saveDontShowAgainContinue(const QString &dontShowAgainName)
420{
421 if (dontShowAgainName.isEmpty()) {
422 return;
423 }
424 dontAskAgainInterface()->saveDontShowAgainContinue(dontShowAgainName);
425}
426
427void enableAllMessages()
428{
429 dontAskAgainInterface()->enableAllMessages();
430}
431
432void enableMessage(const QString &dontShowAgainName)
433{
434 dontAskAgainInterface()->enableMessage(dontShowAgainName);
435}
436
437void setDontShowAgainConfig(KConfig *cfg)
438{
439 dontAskAgainInterface()->setConfig(cfg);
440}
441
442/// @private Prevent kapidox's doxygen config pick up this namespace method
443static ButtonCode questionTwoActionsListInternal(QDialog *dialog,
444 const QString &text,
445 const QStringList &strlist,
446 const QString &title,
447 const KGuiItem &primaryAction,
448 const KGuiItem &secondaryAction,
449 const QString &dontAskAgainName,
450 Options options)
451{
452 ButtonCode res;
453 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
454 delete dialog;
455 return res;
456 }
457
458 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Question") : title);
459 dialog->setObjectName(QStringLiteral("questionTwoActions"));
460
461 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
462 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
463 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
464 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
465
466 applyOptions(dialog, options);
467
468 bool checkboxResult = false;
469 const int result = createKMessageBox(dialog,
470 buttons: buttonBox,
471 icon: QMessageBox::Question,
472 text,
473 strlist,
474 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
475 checkboxReturn: &checkboxResult,
476 options);
477 res = (result == QDialogButtonBox::Yes ? PrimaryAction : SecondaryAction);
478
479 if (checkboxResult) {
480 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
481 }
482 return res;
483}
484
485ButtonCode questionTwoActionsList(QWidget *parent,
486 const QString &text,
487 const QStringList &strlist,
488 const QString &title,
489 const KGuiItem &primaryAction,
490 const KGuiItem &secondaryAction,
491 const QString &dontAskAgainName,
492 Options options)
493{
494 return questionTwoActionsListInternal(dialog: new QDialog(parent), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
495}
496
497/// @private Prevent kapidox's doxygen config pick up this namespace method
498static ButtonCode questionTwoActionsCancelInternal(QDialog *dialog,
499 const QString &text,
500 const QString &title,
501 const KGuiItem &primaryAction,
502 const KGuiItem &secondaryAction,
503 const KGuiItem &cancelAction,
504 const QString &dontAskAgainName,
505 Options options)
506{
507 ButtonCode res;
508 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
509 delete dialog;
510 return res;
511 }
512
513 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Question") : title);
514 dialog->setObjectName(QStringLiteral("QuestionTwoActionsCancel"));
515
516 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
517 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
518 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
519 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
520 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Cancel), item: cancelAction);
521
522 applyOptions(dialog, options);
523
524 bool checkboxResult = false;
525 const int result = createKMessageBox(dialog,
526 buttons: buttonBox,
527 icon: QMessageBox::Question,
528 text,
529 strlist: QStringList(),
530 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
531 checkboxReturn: &checkboxResult,
532 options);
533
534 if (result == QDialogButtonBox::Yes) {
535 res = PrimaryAction;
536 } else if (result == QDialogButtonBox::No) {
537 res = SecondaryAction;
538 } else {
539 return Cancel;
540 }
541
542 if (checkboxResult) {
543 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
544 }
545 return res;
546}
547
548ButtonCode questionTwoActionsCancel(QWidget *parent,
549 const QString &text,
550 const QString &title,
551 const KGuiItem &primaryAction,
552 const KGuiItem &secondaryAction,
553 const KGuiItem &cancelAction,
554 const QString &dontAskAgainName,
555 Options options)
556{
557 return questionTwoActionsCancelInternal(dialog: new QDialog(parent), text, title, primaryAction, secondaryAction, cancelAction, dontAskAgainName, options);
558}
559
560ButtonCode warningTwoActions(QWidget *parent,
561 const QString &text,
562 const QString &title,
563 const KGuiItem &primaryAction,
564 const KGuiItem &secondaryAction,
565 const QString &dontAskAgainName,
566 Options options)
567{
568 return warningTwoActionsList(parent, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
569}
570
571/// @private Prevent kapidox's doxygen config pick up this namespace method
572static ButtonCode warningTwoActionsListInternal(QDialog *dialog,
573 const QString &text,
574 const QStringList &strlist,
575 const QString &title,
576 const KGuiItem &primaryAction,
577 const KGuiItem &secondaryAction,
578 const QString &dontAskAgainName,
579 Options options)
580{
581 ButtonCode res;
582 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
583 delete dialog;
584 return res;
585 }
586
587 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Warning") : title);
588 dialog->setObjectName(QStringLiteral("warningTwoActionsList"));
589
590 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
591 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
592 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
593 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
594
595 applyOptions(dialog, options);
596
597 bool checkboxResult = false;
598 const int result = createKMessageBox(dialog,
599 buttons: buttonBox,
600 icon: QMessageBox::Warning,
601 text,
602 strlist,
603 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
604 checkboxReturn: &checkboxResult,
605 options);
606 res = (result == QDialogButtonBox::Yes ? PrimaryAction : SecondaryAction);
607
608 if (checkboxResult) {
609 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
610 }
611 return res;
612}
613
614ButtonCode warningTwoActionsList(QWidget *parent,
615 const QString &text,
616 const QStringList &strlist,
617 const QString &title,
618 const KGuiItem &primaryAction,
619 const KGuiItem &secondaryAction,
620 const QString &dontAskAgainName,
621 Options options)
622{
623 return warningTwoActionsListInternal(dialog: new QDialog(parent), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
624}
625
626ButtonCode warningContinueCancel(QWidget *parent,
627 const QString &text,
628 const QString &title,
629 const KGuiItem &buttonContinue,
630 const KGuiItem &buttonCancel,
631 const QString &dontAskAgainName,
632 Options options)
633{
634 return warningContinueCancelList(parent, text, strlist: QStringList(), title, buttonContinue, buttonCancel, dontAskAgainName, options);
635}
636
637/// @private Prevent kapidox's doxygen config pick up this namespace method
638static ButtonCode warningContinueCancelListInternal(QDialog *dialog,
639 const QString &text,
640 const QStringList &strlist,
641 const QString &title,
642 const KGuiItem &buttonContinue,
643 const KGuiItem &buttonCancel,
644 const QString &dontAskAgainName,
645 Options options,
646 const QString &details)
647{
648 if (!shouldBeShownContinue(dontShowAgainName: dontAskAgainName)) {
649 delete dialog;
650 return Continue;
651 }
652
653 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Warning") : title);
654 dialog->setObjectName(QStringLiteral("warningYesNo"));
655
656 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
657 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
658 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: buttonContinue);
659 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: buttonCancel);
660
661 applyOptions(dialog, options);
662
663 bool checkboxResult = false;
664 const int result = createKMessageBox(dialog,
665 buttons: buttonBox,
666 icon: QMessageBox::Warning,
667 text,
668 strlist,
669 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
670 checkboxReturn: &checkboxResult,
671 options,
672 details);
673
674 if (result != QDialogButtonBox::Yes) {
675 return Cancel;
676 }
677 if (checkboxResult) {
678 saveDontShowAgainContinue(dontShowAgainName: dontAskAgainName);
679 }
680 return Continue;
681}
682
683ButtonCode warningContinueCancelList(QWidget *parent,
684 const QString &text,
685 const QStringList &strlist,
686 const QString &title,
687 const KGuiItem &buttonContinue,
688 const KGuiItem &buttonCancel,
689 const QString &dontAskAgainName,
690 Options options)
691{
692 return warningContinueCancelListInternal(dialog: new QDialog(parent), text, strlist, title, buttonContinue, buttonCancel, dontAskAgainName, options, details: QString());
693}
694
695ButtonCode warningContinueCancelDetailed(QWidget *parent,
696 const QString &text,
697 const QString &title,
698 const KGuiItem &buttonContinue,
699 const KGuiItem &buttonCancel,
700 const QString &dontAskAgainName,
701 Options options,
702 const QString &details)
703{
704 return warningContinueCancelListInternal(dialog: new QDialog(parent), text, strlist: QStringList(), title, buttonContinue, buttonCancel, dontAskAgainName, options, details);
705}
706
707ButtonCode warningTwoActionsCancel(QWidget *parent,
708 const QString &text,
709 const QString &title,
710 const KGuiItem &primaryAction,
711 const KGuiItem &secondaryAction,
712 const KGuiItem &cancelAction,
713 const QString &dontAskAgainName,
714 Options options)
715{
716 return warningTwoActionsCancelList(parent, text, strlist: QStringList(), title, primaryAction, secondaryAction, cancelAction, dontAskAgainName, options);
717}
718
719/// @private Prevent kapidox's doxygen config pick up this namespace method
720static ButtonCode warningTwoActionsCancelListInternal(QDialog *dialog,
721 const QString &text,
722 const QStringList &strlist,
723 const QString &title,
724 const KGuiItem &primaryAction,
725 const KGuiItem &secondaryAction,
726 const KGuiItem &cancelAction,
727 const QString &dontAskAgainName,
728 Options options)
729{
730 ButtonCode res;
731 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
732 delete dialog;
733 return res;
734 }
735
736 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Warning") : title);
737 dialog->setObjectName(QStringLiteral("warningTwoActionsCancel"));
738
739 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
740 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
741 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
742 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
743 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Cancel), item: cancelAction);
744
745 applyOptions(dialog, options);
746
747 bool checkboxResult = false;
748 const int result = createKMessageBox(dialog,
749 buttons: buttonBox,
750 icon: QMessageBox::Warning,
751 text,
752 strlist,
753 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
754 checkboxReturn: &checkboxResult,
755 options);
756
757 if (result == QDialogButtonBox::Yes) {
758 res = PrimaryAction;
759 } else if (result == QDialogButtonBox::No) {
760 res = SecondaryAction;
761 } else {
762 return Cancel;
763 }
764
765 if (checkboxResult) {
766 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
767 }
768 return res;
769}
770
771ButtonCode warningTwoActionsCancelList(QWidget *parent,
772 const QString &text,
773 const QStringList &strlist,
774 const QString &title,
775 const KGuiItem &primaryAction,
776 const KGuiItem &secondaryAction,
777 const KGuiItem &cancelAction,
778 const QString &dontAskAgainName,
779 Options options)
780{
781 return warningTwoActionsCancelListInternal(dialog: new QDialog(parent),
782 text,
783 strlist,
784 title,
785 primaryAction,
786 secondaryAction,
787 cancelAction,
788 dontAskAgainName,
789 options);
790}
791
792/// @private Prevent kapidox's doxygen config pick up this namespace method
793static void errorInternal(QDialog *dialog, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options)
794{
795 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Error") : title);
796 dialog->setObjectName(QStringLiteral("error"));
797
798 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
799 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
800 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Ok), item: buttonOk);
801
802 applyOptions(dialog, options);
803
804 createKMessageBox(dialog, buttons: buttonBox, icon: QMessageBox::Critical, text, strlist: QStringList(), ask: QString(), checkboxReturn: nullptr, options);
805}
806
807void error(QWidget *parent, const QString &text, const QString &title, Options options)
808{
809 errorInternal(dialog: new QDialog(parent), text, title, buttonOk: KStandardGuiItem::ok(), options);
810}
811
812void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options)
813{
814 errorInternal(dialog: new QDialog(parent), text, title, buttonOk, options);
815}
816
817/// @private Prevent kapidox's doxygen config pick up this namespace method
818static void errorListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &title, Options options)
819{
820 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Error") : title);
821 dialog->setObjectName(QStringLiteral("error"));
822
823 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
824 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
825
826 applyOptions(dialog, options);
827
828 createKMessageBox(dialog, buttons: buttonBox, icon: QMessageBox::Critical, text, strlist, ask: QString(), checkboxReturn: nullptr, options);
829}
830
831void errorList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title, Options options)
832{
833 errorListInternal(dialog: new QDialog(parent), text, strlist, title, options);
834}
835
836/// @private Prevent kapidox's doxygen config pick up this namespace method
837static void detailedErrorInternal(QDialog *dialog, const QString &text, const QString &details, const QString &title, const KGuiItem &buttonOk, Options options)
838{
839 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Error") : title);
840 dialog->setObjectName(QStringLiteral("error"));
841
842 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
843 buttonBox->addButton(button: QDialogButtonBox::Ok);
844 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Ok), item: buttonOk);
845 buttonBox->button(which: QDialogButtonBox::Ok)->setFocus();
846
847 applyOptions(dialog, options);
848
849 createKMessageBox(dialog, buttons: buttonBox, icon: QMessageBox::Critical, text, strlist: QStringList(), ask: QString(), checkboxReturn: nullptr, options, details);
850}
851
852void detailedError(QWidget *parent, const QString &text, const QString &details, const QString &title, Options options)
853{
854 detailedErrorInternal(dialog: new QDialog(parent), text, details, title, buttonOk: KStandardGuiItem::ok(), options);
855}
856
857void detailedError(QWidget *parent, const QString &text, const QString &details, const QString &title, const KGuiItem &buttonOk, Options options)
858{
859 detailedErrorInternal(dialog: new QDialog(parent), text, details, title, buttonOk, options);
860}
861
862void information(QWidget *parent, const QString &text, const QString &title, const QString &dontShowAgainName, Options options)
863{
864 informationList(parent, text, strlist: QStringList(), title, dontShowAgainName, options);
865}
866
867/// @private Prevent kapidox's doxygen config pick up this namespace method
868static void informationListInternal(QDialog *dialog,
869 const QString &text,
870 const QStringList &strlist,
871 const QString &title,
872 const QString &dontShowAgainName,
873 Options options)
874{
875 if (!shouldBeShownContinue(dontShowAgainName)) {
876 delete dialog;
877 return;
878 }
879
880 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Information") : title);
881 dialog->setObjectName(QStringLiteral("information"));
882
883 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
884 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
885
886 applyOptions(dialog, options);
887
888 bool checkboxResult = false;
889
890 createKMessageBox(dialog,
891 buttons: buttonBox,
892 icon: QMessageBox::Information,
893 text,
894 strlist,
895 ask: dontShowAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not show this message again"),
896 checkboxReturn: &checkboxResult,
897 options);
898
899 if (checkboxResult) {
900 saveDontShowAgainContinue(dontShowAgainName);
901 }
902}
903
904void informationList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title, const QString &dontShowAgainName, Options options)
905{
906 informationListInternal(dialog: new QDialog(parent), text, strlist, title, dontShowAgainName, options);
907}
908
909/// @private Prevent kapidox's doxygen config pick up this namespace method
910static ButtonCode messageBoxInternal(QDialog *dialog,
911 DialogType type,
912 const QString &text,
913 const QString &title,
914 const KGuiItem &primaryAction,
915 const KGuiItem &secondaryAction,
916 const KGuiItem &cancelAction,
917 const QString &dontShow,
918 Options options)
919{
920 switch (type) {
921 case QuestionTwoActions:
922 return questionTwoActionsListInternal(dialog, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName: dontShow, options);
923 case QuestionTwoActionsCancel:
924 return questionTwoActionsCancelInternal(dialog, text, title, primaryAction, secondaryAction, cancelAction, dontAskAgainName: dontShow, options);
925 case WarningTwoActions:
926 return warningTwoActionsListInternal(dialog, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName: dontShow, options);
927 case WarningContinueCancel:
928 return warningContinueCancelListInternal(dialog,
929 text,
930 strlist: QStringList(),
931 title,
932 buttonContinue: KGuiItem(primaryAction.text()),
933 buttonCancel: cancelAction,
934 dontAskAgainName: dontShow,
935 options,
936 details: QString());
937 case WarningTwoActionsCancel:
938 return warningTwoActionsCancelListInternal(dialog, text, strlist: QStringList(), title, primaryAction, secondaryAction, cancelAction, dontAskAgainName: dontShow, options);
939 case Information:
940 informationListInternal(dialog, text, strlist: QStringList(), title, dontShowAgainName: dontShow, options);
941 return KMessageBox::Ok;
942
943 case Error:
944 errorListInternal(dialog, text, strlist: QStringList(), title, options);
945 return KMessageBox::Ok;
946 }
947 return KMessageBox::Cancel;
948}
949
950ButtonCode messageBox(QWidget *parent,
951 DialogType type,
952 const QString &text,
953 const QString &title,
954 const KGuiItem &primaryAction,
955 const KGuiItem &secondaryAction,
956 const KGuiItem &buttonCancel,
957 const QString &dontShow,
958 Options options)
959{
960 return messageBoxInternal(dialog: new QDialog(parent), type, text, title, primaryAction, secondaryAction, cancelAction: buttonCancel, dontShow, options);
961}
962
963ButtonCode questionTwoActionsWId(WId parent_id,
964 const QString &text,
965 const QString &title,
966 const KGuiItem &primaryAction,
967 const KGuiItem &secondaryAction,
968 const QString &dontAskAgainName,
969 Options options)
970{
971 return questionTwoActionsListWId(parent_id, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
972}
973
974ButtonCode questionTwoActionsListWId(WId parent_id,
975 const QString &text,
976 const QStringList &strlist,
977 const QString &title,
978 const KGuiItem &primaryAction,
979 const KGuiItem &secondaryAction,
980 const QString &dontAskAgainName,
981 Options options)
982{
983 return questionTwoActionsListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
984}
985
986ButtonCode questionTwoActionsCancelWId(WId parent_id,
987 const QString &text,
988 const QString &title,
989 const KGuiItem &primaryAction,
990 const KGuiItem &secondaryAction,
991 const KGuiItem &cancelAction,
992 const QString &dontAskAgainName,
993 Options options)
994{
995 return questionTwoActionsCancelInternal(dialog: createWIdDialog(parent_id), text, title, primaryAction, secondaryAction, cancelAction, dontAskAgainName, options);
996}
997
998ButtonCode warningTwoActionsWId(WId parent_id,
999 const QString &text,
1000 const QString &title,
1001 const KGuiItem &primaryAction,
1002 const KGuiItem &secondaryAction,
1003 const QString &dontAskAgainName,
1004 Options options)
1005{
1006 return warningTwoActionsListWId(parent_id, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
1007}
1008
1009ButtonCode warningTwoActionsListWId(WId parent_id,
1010 const QString &text,
1011 const QStringList &strlist,
1012 const QString &title,
1013 const KGuiItem &primaryAction,
1014 const KGuiItem &secondaryAction,
1015 const QString &dontAskAgainName,
1016 Options options)
1017{
1018 return warningTwoActionsListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
1019}
1020
1021ButtonCode warningContinueCancelWId(WId parent_id,
1022 const QString &text,
1023 const QString &title,
1024 const KGuiItem &buttonContinue,
1025 const KGuiItem &buttonCancel,
1026 const QString &dontAskAgainName,
1027 Options options)
1028{
1029 return warningContinueCancelListWId(parent_id, text, strlist: QStringList(), title, buttonContinue, buttonCancel, dontAskAgainName, options);
1030}
1031
1032ButtonCode warningContinueCancelListWId(WId parent_id,
1033 const QString &text,
1034 const QStringList &strlist,
1035 const QString &title,
1036 const KGuiItem &buttonContinue,
1037 const KGuiItem &buttonCancel,
1038 const QString &dontAskAgainName,
1039 Options options)
1040{
1041 return warningContinueCancelListInternal(dialog: createWIdDialog(parent_id),
1042 text,
1043 strlist,
1044 title,
1045 buttonContinue,
1046 buttonCancel,
1047 dontAskAgainName,
1048 options,
1049 details: QString());
1050}
1051
1052ButtonCode warningTwoActionsCancelWId(WId parent_id,
1053 const QString &text,
1054 const QString &title,
1055 const KGuiItem &primaryAction,
1056 const KGuiItem &secondaryAction,
1057 const KGuiItem &buttonCancel,
1058 const QString &dontAskAgainName,
1059 Options options)
1060{
1061 return warningTwoActionsCancelListWId(parent_id, text, strlist: QStringList(), title, primaryAction, secondaryAction, cancelAction: buttonCancel, dontAskAgainName, options);
1062}
1063
1064ButtonCode warningTwoActionsCancelListWId(WId parent_id,
1065 const QString &text,
1066 const QStringList &strlist,
1067 const QString &title,
1068 const KGuiItem &primaryAction,
1069 const KGuiItem &secondaryAction,
1070 const KGuiItem &buttonCancel,
1071 const QString &dontAskAgainName,
1072 Options options)
1073{
1074 return warningTwoActionsCancelList(parent: createWIdDialog(parent_id),
1075 text,
1076 strlist,
1077 title,
1078 primaryAction,
1079 secondaryAction,
1080 cancelAction: buttonCancel,
1081 dontAskAgainName,
1082 options);
1083}
1084
1085void errorWId(WId parent_id, const QString &text, const QString &title, Options options)
1086{
1087 errorListWId(parent_id, text, strlist: QStringList(), title, options);
1088}
1089
1090void errorListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &title, Options options)
1091{
1092 errorListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, options);
1093}
1094
1095void detailedErrorWId(WId parent_id, const QString &text, const QString &details, const QString &title, Options options)
1096{
1097 detailedErrorInternal(dialog: createWIdDialog(parent_id), text, details, title, buttonOk: KStandardGuiItem::ok(), options);
1098}
1099
1100void detailedErrorWId(WId parent_id, const QString &text, const QString &details, const QString &title, const KGuiItem &buttonOk, Options options)
1101{
1102 detailedErrorInternal(dialog: createWIdDialog(parent_id), text, details, title, buttonOk, options);
1103}
1104
1105void informationWId(WId parent_id, const QString &text, const QString &title, const QString &dontShowAgainName, Options options)
1106{
1107 informationListWId(parent_id, text, strlist: QStringList(), title, dontShowAgainName, options);
1108}
1109
1110void informationListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &title, const QString &dontShowAgainName, Options options)
1111{
1112 informationListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, dontShowAgainName, options);
1113}
1114
1115ButtonCode messageBoxWId(WId parent_id,
1116 DialogType type,
1117 const QString &text,
1118 const QString &title,
1119 const KGuiItem &primaryAction,
1120 const KGuiItem &secondaryAction,
1121 const KGuiItem &cancelAction,
1122 const QString &dontShow,
1123 Options options)
1124{
1125 return messageBoxInternal(dialog: createWIdDialog(parent_id), type, text, title, primaryAction, secondaryAction, cancelAction, dontShow, options);
1126}
1127
1128} // namespace
1129
1130#include "kmessagebox.moc"
1131

source code of kwidgetsaddons/src/kmessagebox.cpp