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 if (options & Option::PlainText) {
222 messageLabel->setTextFormat(Qt::PlainText);
223 }
224 Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse;
225 if (options & KMessageBox::AllowLink) {
226 flags |= Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard;
227 }
228 messageLabel->setTextInteractionFlags(flags);
229
230 QRect desktop = dialog->screen()->geometry();
231 bool usingSqueezedTextLabel = false;
232 if (messageLabel->sizeHint().width() > desktop.width() * 0.5) {
233 // enable automatic wrapping of messages which are longer than 50% of screen width
234 messageLabel->setWordWrap(true);
235 // use a squeezed label if text is still too wide
236 usingSqueezedTextLabel = messageLabel->sizeHint().width() > desktop.width() * 0.85;
237 if (usingSqueezedTextLabel) {
238 delete messageLabel;
239 messageLabel = new KSqueezedTextLabel(text, mainWidget);
240 messageLabel->setOpenExternalLinks(options & KMessageBox::AllowLink);
241 messageLabel->setTextInteractionFlags(flags);
242 }
243 }
244
245 QPalette messagePal(messageLabel->palette());
246 messagePal.setColor(acr: QPalette::Window, acolor: Qt::transparent);
247 messageLabel->setPalette(messagePal);
248
249 bool usingScrollArea = desktop.height() / 3 < messageLabel->sizeHint().height();
250 if (usingScrollArea) {
251 QScrollArea *messageScrollArea = new QScrollArea(mainWidget);
252 messageScrollArea->setWidget(messageLabel);
253 messageScrollArea->setFrameShape(QFrame::NoFrame);
254 messageScrollArea->setWidgetResizable(true);
255 QPalette scrollPal(messageScrollArea->palette());
256 scrollPal.setColor(acr: QPalette::Window, acolor: Qt::transparent);
257 messageScrollArea->viewport()->setPalette(scrollPal);
258 hLayout->addWidget(messageScrollArea, stretch: 5);
259 } else {
260 hLayout->addWidget(messageLabel, stretch: 5);
261 }
262
263 const bool usingListWidget = !strlist.isEmpty();
264 if (usingListWidget) {
265 // enable automatic wrapping since the listwidget has already a good initial width
266 messageLabel->setWordWrap(true);
267 QListWidget *listWidget = new QListWidget(mainWidget);
268 listWidget->addItems(labels: strlist);
269
270 QStyleOptionViewItem styleOption;
271 styleOption.initFrom(w: listWidget);
272 QFontMetrics fm(styleOption.font);
273 int w = listWidget->width();
274 for (const QString &str : strlist) {
275 w = qMax(a: w, b: fm.boundingRect(text: str).width());
276 }
277 const int borderWidth = listWidget->width() - listWidget->viewport()->width() + listWidget->verticalScrollBar()->height();
278 w += borderWidth;
279 if (w > desktop.width() * 0.85) { // limit listWidget size to 85% of screen width
280 w = qRound(d: desktop.width() * 0.85);
281 }
282 listWidget->setMinimumWidth(w);
283
284 mainLayout->addWidget(listWidget, stretch: usingScrollArea ? 10 : 50);
285 listWidget->setSelectionMode(QListWidget::NoSelection);
286 messageLabel->setSizePolicy(hor: QSizePolicy::Preferred, ver: QSizePolicy::Minimum);
287 } else if (!usingScrollArea) {
288 mainLayout->addStretch(stretch: 15);
289 }
290
291 QPointer<QCheckBox> checkbox = nullptr;
292 if (!ask.isEmpty()) {
293 checkbox = new QCheckBox(ask, mainWidget);
294 mainLayout->addWidget(checkbox);
295 if (checkboxReturn) {
296 checkbox->setChecked(*checkboxReturn);
297 }
298 }
299
300 QVBoxLayout *topLayout = new QVBoxLayout(dialog);
301 topLayout->addWidget(mainWidget);
302
303 if (!details.isEmpty()) {
304 QHBoxLayout *detailsHLayout = new QHBoxLayout();
305 detailsHLayout->addSpacing(size: 2 * horizontalSpacing + iconLayout->sizeHint().width());
306 KCollapsibleGroupBox *detailsGroup = new KCollapsibleGroupBox();
307 detailsGroup->setTitle(QApplication::translate(context: "KMessageBox", key: "Details"));
308 QVBoxLayout *detailsLayout = new QVBoxLayout(detailsGroup);
309 if (details.length() < 512) {
310 QLabel *detailsLabel = new QLabel(details);
311 detailsLabel->setOpenExternalLinks(options & KMessageBox::AllowLink);
312 Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse;
313 if (options & KMessageBox::AllowLink) {
314 flags |= Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard;
315 };
316 detailsLabel->setTextInteractionFlags(flags);
317 detailsLabel->setWordWrap(true);
318 detailsLabel->setMinimumSize(detailsLabel->sizeHint());
319 detailsLayout->addWidget(detailsLabel, stretch: 50);
320 } else {
321 QTextBrowser *detailTextEdit = new QTextBrowser();
322 detailTextEdit->setText(details);
323 detailTextEdit->setReadOnly(true);
324 detailTextEdit->setMinimumHeight(detailTextEdit->fontMetrics().lineSpacing() * 11);
325 detailsLayout->addWidget(detailTextEdit, stretch: 50);
326 }
327 if (!usingListWidget) {
328 mainLayout->setStretchFactor(l: hLayout, stretch: 10);
329 }
330 detailsHLayout->addWidget(detailsGroup);
331 topLayout->addLayout(layout: detailsHLayout);
332 buttonsHelper->setDetailsWidget(detailsGroup);
333 }
334
335 topLayout->addWidget(buttons);
336 topLayout->setSizeConstraint(QLayout::SetFixedSize);
337
338 if (!usingListWidget && !usingScrollArea && !usingSqueezedTextLabel && details.isEmpty()) {
339 dialog->setFixedSize(dialog->sizeHint() + QSize(10, 10));
340 }
341
342 if ((options & KMessageBox::Dangerous)) {
343 QPushButton *cancelButton = buttons->button(which: QDialogButtonBox::Cancel);
344 QPushButton *noButton = buttons->button(which: QDialogButtonBox::No);
345
346 if (cancelButton && cancelButton->isEnabled()) {
347 cancelButton->setDefault(true);
348 cancelButton->setFocus();
349 } else if (noButton && noButton->isEnabled()) {
350 noButton->setDefault(true);
351 noButton->setFocus();
352 }
353 }
354
355#ifndef Q_OS_WIN // FIXME problems with KNotify on Windows
356 if ((options & KMessageBox::Notify)) {
357 QString message = text;
358 if (!strlist.isEmpty()) {
359 message += QLatin1Char('\n') + strlist.join(sep: QLatin1Char('\n'));
360 }
361 notifyInterface()->sendNotification(notificationType: notifyType, message, parent: dialog->topLevelWidget());
362 }
363#endif
364
365 if (KMessageBox_exec_hook) {
366 return KMessageBox_exec_hook(dialog);
367 }
368
369 if ((options & KMessageBox::NoExec)) {
370 return QDialogButtonBox::NoButton; // We have to return something.
371 }
372
373 // We use a QPointer because the dialog may get deleted
374 // during exec() if the parent of the dialog gets deleted.
375 // In that case the QPointer will reset to 0.
376 QPointer<QDialog> guardedDialog = dialog;
377
378 const QDialogButtonBox::StandardButton result = QDialogButtonBox::StandardButton(guardedDialog->exec());
379 if (checkbox && checkboxReturn) {
380 *checkboxReturn = checkbox->isChecked();
381 }
382
383 delete guardedDialog;
384 return result;
385}
386
387ButtonCode questionTwoActions(QWidget *parent,
388 const QString &text,
389 const QString &title,
390 const KGuiItem &primaryAction,
391 const KGuiItem &secondaryAction,
392 const QString &dontAskAgainName,
393 Options options)
394{
395 return questionTwoActionsList(parent, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
396}
397
398bool shouldBeShownTwoActions(const QString &dontShowAgainName, ButtonCode &result)
399{
400 if (dontShowAgainName.isEmpty()) {
401 return true;
402 }
403 return dontAskAgainInterface()->shouldBeShownTwoActions(dontShowAgainName, result);
404}
405
406bool shouldBeShownContinue(const QString &dontShowAgainName)
407{
408 if (dontShowAgainName.isEmpty()) {
409 return true;
410 }
411 return dontAskAgainInterface()->shouldBeShownContinue(dontShowAgainName);
412}
413
414void saveDontShowAgainTwoActions(const QString &dontShowAgainName, ButtonCode result)
415{
416 if (dontShowAgainName.isEmpty()) {
417 return;
418 }
419 dontAskAgainInterface()->saveDontShowAgainTwoActions(dontShowAgainName, result);
420}
421
422void saveDontShowAgainContinue(const QString &dontShowAgainName)
423{
424 if (dontShowAgainName.isEmpty()) {
425 return;
426 }
427 dontAskAgainInterface()->saveDontShowAgainContinue(dontShowAgainName);
428}
429
430void enableAllMessages()
431{
432 dontAskAgainInterface()->enableAllMessages();
433}
434
435void enableMessage(const QString &dontShowAgainName)
436{
437 dontAskAgainInterface()->enableMessage(dontShowAgainName);
438}
439
440void setDontShowAgainConfig(KConfig *cfg)
441{
442 dontAskAgainInterface()->setConfig(cfg);
443}
444
445/// @private Prevent kapidox's doxygen config pick up this namespace method
446static ButtonCode questionTwoActionsListInternal(QDialog *dialog,
447 const QString &text,
448 const QStringList &strlist,
449 const QString &title,
450 const KGuiItem &primaryAction,
451 const KGuiItem &secondaryAction,
452 const QString &dontAskAgainName,
453 Options options)
454{
455 ButtonCode res;
456 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
457 delete dialog;
458 return res;
459 }
460
461 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Question") : title);
462 dialog->setObjectName(QStringLiteral("questionTwoActions"));
463
464 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
465 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
466 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
467 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
468
469 applyOptions(dialog, options);
470
471 bool checkboxResult = false;
472 const int result = createKMessageBox(dialog,
473 buttons: buttonBox,
474 icon: QMessageBox::Question,
475 text,
476 strlist,
477 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
478 checkboxReturn: &checkboxResult,
479 options);
480 res = (result == QDialogButtonBox::Yes ? PrimaryAction : SecondaryAction);
481
482 if (checkboxResult) {
483 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
484 }
485 return res;
486}
487
488ButtonCode questionTwoActionsList(QWidget *parent,
489 const QString &text,
490 const QStringList &strlist,
491 const QString &title,
492 const KGuiItem &primaryAction,
493 const KGuiItem &secondaryAction,
494 const QString &dontAskAgainName,
495 Options options)
496{
497 return questionTwoActionsListInternal(dialog: new QDialog(parent), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
498}
499
500/// @private Prevent kapidox's doxygen config pick up this namespace method
501static ButtonCode questionTwoActionsCancelInternal(QDialog *dialog,
502 const QString &text,
503 const QString &title,
504 const KGuiItem &primaryAction,
505 const KGuiItem &secondaryAction,
506 const KGuiItem &cancelAction,
507 const QString &dontAskAgainName,
508 Options options)
509{
510 ButtonCode res;
511 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
512 delete dialog;
513 return res;
514 }
515
516 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Question") : title);
517 dialog->setObjectName(QStringLiteral("QuestionTwoActionsCancel"));
518
519 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
520 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
521 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
522 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
523 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Cancel), item: cancelAction);
524
525 applyOptions(dialog, options);
526
527 bool checkboxResult = false;
528 const int result = createKMessageBox(dialog,
529 buttons: buttonBox,
530 icon: QMessageBox::Question,
531 text,
532 strlist: QStringList(),
533 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
534 checkboxReturn: &checkboxResult,
535 options);
536
537 if (result == QDialogButtonBox::Yes) {
538 res = PrimaryAction;
539 } else if (result == QDialogButtonBox::No) {
540 res = SecondaryAction;
541 } else {
542 return Cancel;
543 }
544
545 if (checkboxResult) {
546 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
547 }
548 return res;
549}
550
551ButtonCode questionTwoActionsCancel(QWidget *parent,
552 const QString &text,
553 const QString &title,
554 const KGuiItem &primaryAction,
555 const KGuiItem &secondaryAction,
556 const KGuiItem &cancelAction,
557 const QString &dontAskAgainName,
558 Options options)
559{
560 return questionTwoActionsCancelInternal(dialog: new QDialog(parent), text, title, primaryAction, secondaryAction, cancelAction, dontAskAgainName, options);
561}
562
563ButtonCode warningTwoActions(QWidget *parent,
564 const QString &text,
565 const QString &title,
566 const KGuiItem &primaryAction,
567 const KGuiItem &secondaryAction,
568 const QString &dontAskAgainName,
569 Options options)
570{
571 return warningTwoActionsList(parent, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
572}
573
574/// @private Prevent kapidox's doxygen config pick up this namespace method
575static ButtonCode warningTwoActionsListInternal(QDialog *dialog,
576 const QString &text,
577 const QStringList &strlist,
578 const QString &title,
579 const KGuiItem &primaryAction,
580 const KGuiItem &secondaryAction,
581 const QString &dontAskAgainName,
582 Options options)
583{
584 ButtonCode res;
585 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
586 delete dialog;
587 return res;
588 }
589
590 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Warning") : title);
591 dialog->setObjectName(QStringLiteral("warningTwoActionsList"));
592
593 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
594 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
595 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
596 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
597
598 applyOptions(dialog, options);
599
600 bool checkboxResult = false;
601 const int result = createKMessageBox(dialog,
602 buttons: buttonBox,
603 icon: QMessageBox::Warning,
604 text,
605 strlist,
606 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
607 checkboxReturn: &checkboxResult,
608 options);
609 res = (result == QDialogButtonBox::Yes ? PrimaryAction : SecondaryAction);
610
611 if (checkboxResult) {
612 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
613 }
614 return res;
615}
616
617ButtonCode warningTwoActionsList(QWidget *parent,
618 const QString &text,
619 const QStringList &strlist,
620 const QString &title,
621 const KGuiItem &primaryAction,
622 const KGuiItem &secondaryAction,
623 const QString &dontAskAgainName,
624 Options options)
625{
626 return warningTwoActionsListInternal(dialog: new QDialog(parent), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
627}
628
629ButtonCode warningContinueCancel(QWidget *parent,
630 const QString &text,
631 const QString &title,
632 const KGuiItem &buttonContinue,
633 const KGuiItem &buttonCancel,
634 const QString &dontAskAgainName,
635 Options options)
636{
637 return warningContinueCancelList(parent, text, strlist: QStringList(), title, buttonContinue, buttonCancel, dontAskAgainName, options);
638}
639
640/// @private Prevent kapidox's doxygen config pick up this namespace method
641static ButtonCode warningContinueCancelListInternal(QDialog *dialog,
642 const QString &text,
643 const QStringList &strlist,
644 const QString &title,
645 const KGuiItem &buttonContinue,
646 const KGuiItem &buttonCancel,
647 const QString &dontAskAgainName,
648 Options options,
649 const QString &details)
650{
651 if (!shouldBeShownContinue(dontShowAgainName: dontAskAgainName)) {
652 delete dialog;
653 return Continue;
654 }
655
656 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Warning") : title);
657 dialog->setObjectName(QStringLiteral("warningYesNo"));
658
659 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
660 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
661 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: buttonContinue);
662 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: buttonCancel);
663
664 applyOptions(dialog, options);
665
666 bool checkboxResult = false;
667 const int result = createKMessageBox(dialog,
668 buttons: buttonBox,
669 icon: QMessageBox::Warning,
670 text,
671 strlist,
672 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
673 checkboxReturn: &checkboxResult,
674 options,
675 details);
676
677 if (result != QDialogButtonBox::Yes) {
678 return Cancel;
679 }
680 if (checkboxResult) {
681 saveDontShowAgainContinue(dontShowAgainName: dontAskAgainName);
682 }
683 return Continue;
684}
685
686ButtonCode warningContinueCancelList(QWidget *parent,
687 const QString &text,
688 const QStringList &strlist,
689 const QString &title,
690 const KGuiItem &buttonContinue,
691 const KGuiItem &buttonCancel,
692 const QString &dontAskAgainName,
693 Options options)
694{
695 return warningContinueCancelListInternal(dialog: new QDialog(parent), text, strlist, title, buttonContinue, buttonCancel, dontAskAgainName, options, details: QString());
696}
697
698ButtonCode warningContinueCancelDetailed(QWidget *parent,
699 const QString &text,
700 const QString &title,
701 const KGuiItem &buttonContinue,
702 const KGuiItem &buttonCancel,
703 const QString &dontAskAgainName,
704 Options options,
705 const QString &details)
706{
707 return warningContinueCancelListInternal(dialog: new QDialog(parent), text, strlist: QStringList(), title, buttonContinue, buttonCancel, dontAskAgainName, options, details);
708}
709
710ButtonCode warningTwoActionsCancel(QWidget *parent,
711 const QString &text,
712 const QString &title,
713 const KGuiItem &primaryAction,
714 const KGuiItem &secondaryAction,
715 const KGuiItem &cancelAction,
716 const QString &dontAskAgainName,
717 Options options)
718{
719 return warningTwoActionsCancelList(parent, text, strlist: QStringList(), title, primaryAction, secondaryAction, cancelAction, dontAskAgainName, options);
720}
721
722/// @private Prevent kapidox's doxygen config pick up this namespace method
723static ButtonCode warningTwoActionsCancelListInternal(QDialog *dialog,
724 const QString &text,
725 const QStringList &strlist,
726 const QString &title,
727 const KGuiItem &primaryAction,
728 const KGuiItem &secondaryAction,
729 const KGuiItem &cancelAction,
730 const QString &dontAskAgainName,
731 Options options)
732{
733 ButtonCode res;
734 if (!shouldBeShownTwoActions(dontShowAgainName: dontAskAgainName, result&: res)) {
735 delete dialog;
736 return res;
737 }
738
739 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Warning") : title);
740 dialog->setObjectName(QStringLiteral("warningTwoActionsCancel"));
741
742 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
743 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
744 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Yes), item: primaryAction);
745 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::No), item: secondaryAction);
746 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Cancel), item: cancelAction);
747
748 applyOptions(dialog, options);
749
750 bool checkboxResult = false;
751 const int result = createKMessageBox(dialog,
752 buttons: buttonBox,
753 icon: QMessageBox::Warning,
754 text,
755 strlist,
756 ask: dontAskAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not ask again"),
757 checkboxReturn: &checkboxResult,
758 options);
759
760 if (result == QDialogButtonBox::Yes) {
761 res = PrimaryAction;
762 } else if (result == QDialogButtonBox::No) {
763 res = SecondaryAction;
764 } else {
765 return Cancel;
766 }
767
768 if (checkboxResult) {
769 saveDontShowAgainTwoActions(dontShowAgainName: dontAskAgainName, result: res);
770 }
771 return res;
772}
773
774ButtonCode warningTwoActionsCancelList(QWidget *parent,
775 const QString &text,
776 const QStringList &strlist,
777 const QString &title,
778 const KGuiItem &primaryAction,
779 const KGuiItem &secondaryAction,
780 const KGuiItem &cancelAction,
781 const QString &dontAskAgainName,
782 Options options)
783{
784 return warningTwoActionsCancelListInternal(dialog: new QDialog(parent),
785 text,
786 strlist,
787 title,
788 primaryAction,
789 secondaryAction,
790 cancelAction,
791 dontAskAgainName,
792 options);
793}
794
795/// @private Prevent kapidox's doxygen config pick up this namespace method
796static void errorInternal(QDialog *dialog, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options)
797{
798 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Error") : title);
799 dialog->setObjectName(QStringLiteral("error"));
800
801 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
802 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
803 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Ok), item: buttonOk);
804
805 applyOptions(dialog, options);
806
807 createKMessageBox(dialog, buttons: buttonBox, icon: QMessageBox::Critical, text, strlist: QStringList(), ask: QString(), checkboxReturn: nullptr, options);
808}
809
810void error(QWidget *parent, const QString &text, const QString &title, Options options)
811{
812 errorInternal(dialog: new QDialog(parent), text, title, buttonOk: KStandardGuiItem::ok(), options);
813}
814
815void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options)
816{
817 errorInternal(dialog: new QDialog(parent), text, title, buttonOk, options);
818}
819
820/// @private Prevent kapidox's doxygen config pick up this namespace method
821static void errorListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &title, Options options)
822{
823 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Error") : title);
824 dialog->setObjectName(QStringLiteral("error"));
825
826 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
827 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
828
829 applyOptions(dialog, options);
830
831 createKMessageBox(dialog, buttons: buttonBox, icon: QMessageBox::Critical, text, strlist, ask: QString(), checkboxReturn: nullptr, options);
832}
833
834void errorList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title, Options options)
835{
836 errorListInternal(dialog: new QDialog(parent), text, strlist, title, options);
837}
838
839/// @private Prevent kapidox's doxygen config pick up this namespace method
840static void detailedErrorInternal(QDialog *dialog, const QString &text, const QString &details, const QString &title, const KGuiItem &buttonOk, Options options)
841{
842 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Error") : title);
843 dialog->setObjectName(QStringLiteral("error"));
844
845 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
846 buttonBox->addButton(button: QDialogButtonBox::Ok);
847 KGuiItem::assign(button: buttonBox->button(which: QDialogButtonBox::Ok), item: buttonOk);
848 buttonBox->button(which: QDialogButtonBox::Ok)->setFocus();
849
850 applyOptions(dialog, options);
851
852 createKMessageBox(dialog, buttons: buttonBox, icon: QMessageBox::Critical, text, strlist: QStringList(), ask: QString(), checkboxReturn: nullptr, options, details);
853}
854
855void detailedError(QWidget *parent, const QString &text, const QString &details, const QString &title, Options options)
856{
857 detailedErrorInternal(dialog: new QDialog(parent), text, details, title, buttonOk: KStandardGuiItem::ok(), options);
858}
859
860void detailedError(QWidget *parent, const QString &text, const QString &details, const QString &title, const KGuiItem &buttonOk, Options options)
861{
862 detailedErrorInternal(dialog: new QDialog(parent), text, details, title, buttonOk, options);
863}
864
865void information(QWidget *parent, const QString &text, const QString &title, const QString &dontShowAgainName, Options options)
866{
867 informationList(parent, text, strlist: QStringList(), title, dontShowAgainName, options);
868}
869
870/// @private Prevent kapidox's doxygen config pick up this namespace method
871static void informationListInternal(QDialog *dialog,
872 const QString &text,
873 const QStringList &strlist,
874 const QString &title,
875 const QString &dontShowAgainName,
876 Options options)
877{
878 if (!shouldBeShownContinue(dontShowAgainName)) {
879 delete dialog;
880 return;
881 }
882
883 dialog->setWindowTitle(title.isEmpty() ? QApplication::translate(context: "KMessageBox", key: "Information") : title);
884 dialog->setObjectName(QStringLiteral("information"));
885
886 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
887 buttonBox->setStandardButtons(QDialogButtonBox::Ok);
888
889 applyOptions(dialog, options);
890
891 bool checkboxResult = false;
892
893 createKMessageBox(dialog,
894 buttons: buttonBox,
895 icon: QMessageBox::Information,
896 text,
897 strlist,
898 ask: dontShowAgainName.isEmpty() ? QString() : QApplication::translate(context: "KMessageBox", key: "Do not show this message again"),
899 checkboxReturn: &checkboxResult,
900 options);
901
902 if (checkboxResult) {
903 saveDontShowAgainContinue(dontShowAgainName);
904 }
905}
906
907void informationList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title, const QString &dontShowAgainName, Options options)
908{
909 informationListInternal(dialog: new QDialog(parent), text, strlist, title, dontShowAgainName, options);
910}
911
912/// @private Prevent kapidox's doxygen config pick up this namespace method
913static ButtonCode messageBoxInternal(QDialog *dialog,
914 DialogType type,
915 const QString &text,
916 const QString &title,
917 const KGuiItem &primaryAction,
918 const KGuiItem &secondaryAction,
919 const KGuiItem &cancelAction,
920 const QString &dontShow,
921 Options options)
922{
923 switch (type) {
924 case QuestionTwoActions:
925 return questionTwoActionsListInternal(dialog, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName: dontShow, options);
926 case QuestionTwoActionsCancel:
927 return questionTwoActionsCancelInternal(dialog, text, title, primaryAction, secondaryAction, cancelAction, dontAskAgainName: dontShow, options);
928 case WarningTwoActions:
929 return warningTwoActionsListInternal(dialog, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName: dontShow, options);
930 case WarningContinueCancel:
931 return warningContinueCancelListInternal(dialog,
932 text,
933 strlist: QStringList(),
934 title,
935 buttonContinue: KGuiItem(primaryAction.text()),
936 buttonCancel: cancelAction,
937 dontAskAgainName: dontShow,
938 options,
939 details: QString());
940 case WarningTwoActionsCancel:
941 return warningTwoActionsCancelListInternal(dialog, text, strlist: QStringList(), title, primaryAction, secondaryAction, cancelAction, dontAskAgainName: dontShow, options);
942 case Information:
943 informationListInternal(dialog, text, strlist: QStringList(), title, dontShowAgainName: dontShow, options);
944 return KMessageBox::Ok;
945
946 case Error:
947 errorListInternal(dialog, text, strlist: QStringList(), title, options);
948 return KMessageBox::Ok;
949 }
950 return KMessageBox::Cancel;
951}
952
953ButtonCode messageBox(QWidget *parent,
954 DialogType type,
955 const QString &text,
956 const QString &title,
957 const KGuiItem &primaryAction,
958 const KGuiItem &secondaryAction,
959 const KGuiItem &buttonCancel,
960 const QString &dontShow,
961 Options options)
962{
963 return messageBoxInternal(dialog: new QDialog(parent), type, text, title, primaryAction, secondaryAction, cancelAction: buttonCancel, dontShow, options);
964}
965
966ButtonCode questionTwoActionsWId(WId parent_id,
967 const QString &text,
968 const QString &title,
969 const KGuiItem &primaryAction,
970 const KGuiItem &secondaryAction,
971 const QString &dontAskAgainName,
972 Options options)
973{
974 return questionTwoActionsListWId(parent_id, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
975}
976
977ButtonCode questionTwoActionsListWId(WId parent_id,
978 const QString &text,
979 const QStringList &strlist,
980 const QString &title,
981 const KGuiItem &primaryAction,
982 const KGuiItem &secondaryAction,
983 const QString &dontAskAgainName,
984 Options options)
985{
986 return questionTwoActionsListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
987}
988
989ButtonCode questionTwoActionsCancelWId(WId parent_id,
990 const QString &text,
991 const QString &title,
992 const KGuiItem &primaryAction,
993 const KGuiItem &secondaryAction,
994 const KGuiItem &cancelAction,
995 const QString &dontAskAgainName,
996 Options options)
997{
998 return questionTwoActionsCancelInternal(dialog: createWIdDialog(parent_id), text, title, primaryAction, secondaryAction, cancelAction, dontAskAgainName, options);
999}
1000
1001ButtonCode warningTwoActionsWId(WId parent_id,
1002 const QString &text,
1003 const QString &title,
1004 const KGuiItem &primaryAction,
1005 const KGuiItem &secondaryAction,
1006 const QString &dontAskAgainName,
1007 Options options)
1008{
1009 return warningTwoActionsListWId(parent_id, text, strlist: QStringList(), title, primaryAction, secondaryAction, dontAskAgainName, options);
1010}
1011
1012ButtonCode warningTwoActionsListWId(WId parent_id,
1013 const QString &text,
1014 const QStringList &strlist,
1015 const QString &title,
1016 const KGuiItem &primaryAction,
1017 const KGuiItem &secondaryAction,
1018 const QString &dontAskAgainName,
1019 Options options)
1020{
1021 return warningTwoActionsListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, primaryAction, secondaryAction, dontAskAgainName, options);
1022}
1023
1024ButtonCode warningContinueCancelWId(WId parent_id,
1025 const QString &text,
1026 const QString &title,
1027 const KGuiItem &buttonContinue,
1028 const KGuiItem &buttonCancel,
1029 const QString &dontAskAgainName,
1030 Options options)
1031{
1032 return warningContinueCancelListWId(parent_id, text, strlist: QStringList(), title, buttonContinue, buttonCancel, dontAskAgainName, options);
1033}
1034
1035ButtonCode warningContinueCancelListWId(WId parent_id,
1036 const QString &text,
1037 const QStringList &strlist,
1038 const QString &title,
1039 const KGuiItem &buttonContinue,
1040 const KGuiItem &buttonCancel,
1041 const QString &dontAskAgainName,
1042 Options options)
1043{
1044 return warningContinueCancelListInternal(dialog: createWIdDialog(parent_id),
1045 text,
1046 strlist,
1047 title,
1048 buttonContinue,
1049 buttonCancel,
1050 dontAskAgainName,
1051 options,
1052 details: QString());
1053}
1054
1055ButtonCode warningTwoActionsCancelWId(WId parent_id,
1056 const QString &text,
1057 const QString &title,
1058 const KGuiItem &primaryAction,
1059 const KGuiItem &secondaryAction,
1060 const KGuiItem &buttonCancel,
1061 const QString &dontAskAgainName,
1062 Options options)
1063{
1064 return warningTwoActionsCancelListWId(parent_id, text, strlist: QStringList(), title, primaryAction, secondaryAction, cancelAction: buttonCancel, dontAskAgainName, options);
1065}
1066
1067ButtonCode warningTwoActionsCancelListWId(WId parent_id,
1068 const QString &text,
1069 const QStringList &strlist,
1070 const QString &title,
1071 const KGuiItem &primaryAction,
1072 const KGuiItem &secondaryAction,
1073 const KGuiItem &buttonCancel,
1074 const QString &dontAskAgainName,
1075 Options options)
1076{
1077 return warningTwoActionsCancelList(parent: createWIdDialog(parent_id),
1078 text,
1079 strlist,
1080 title,
1081 primaryAction,
1082 secondaryAction,
1083 cancelAction: buttonCancel,
1084 dontAskAgainName,
1085 options);
1086}
1087
1088void errorWId(WId parent_id, const QString &text, const QString &title, Options options)
1089{
1090 errorListWId(parent_id, text, strlist: QStringList(), title, options);
1091}
1092
1093void errorListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &title, Options options)
1094{
1095 errorListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, options);
1096}
1097
1098void detailedErrorWId(WId parent_id, const QString &text, const QString &details, const QString &title, Options options)
1099{
1100 detailedErrorInternal(dialog: createWIdDialog(parent_id), text, details, title, buttonOk: KStandardGuiItem::ok(), options);
1101}
1102
1103void detailedErrorWId(WId parent_id, const QString &text, const QString &details, const QString &title, const KGuiItem &buttonOk, Options options)
1104{
1105 detailedErrorInternal(dialog: createWIdDialog(parent_id), text, details, title, buttonOk, options);
1106}
1107
1108void informationWId(WId parent_id, const QString &text, const QString &title, const QString &dontShowAgainName, Options options)
1109{
1110 informationListWId(parent_id, text, strlist: QStringList(), title, dontShowAgainName, options);
1111}
1112
1113void informationListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &title, const QString &dontShowAgainName, Options options)
1114{
1115 informationListInternal(dialog: createWIdDialog(parent_id), text, strlist, title, dontShowAgainName, options);
1116}
1117
1118ButtonCode messageBoxWId(WId parent_id,
1119 DialogType type,
1120 const QString &text,
1121 const QString &title,
1122 const KGuiItem &primaryAction,
1123 const KGuiItem &secondaryAction,
1124 const KGuiItem &cancelAction,
1125 const QString &dontShow,
1126 Options options)
1127{
1128 return messageBoxInternal(dialog: createWIdDialog(parent_id), type, text, title, primaryAction, secondaryAction, cancelAction, dontShow, options);
1129}
1130
1131} // namespace
1132
1133#include "kmessagebox.moc"
1134

source code of kwidgetsaddons/src/kmessagebox.cpp