1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2020 Ahmad Samir <a.samirh78@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#ifndef KMESSAGEDIALOG_H
9#define KMESSAGEDIALOG_H
10
11#include <kwidgetsaddons_export.h>
12
13#include <KStandardGuiItem>
14
15#include <QDialog>
16#include <QMessageBox>
17
18#include <memory>
19
20class KMessageDialogPrivate;
21class KGuiItem;
22class QWidget;
23
24/*!
25 * \class KMessageDialog
26 * \inmodule KWidgetsAddons
27 *
28 * \brief KMessageDialog creates a message box similar to the ones you get from KMessageBox,
29 * but that can be used asynchronously, i.e. you can show the dialog by using show()
30 * or open().
31 *
32 * This class contructs a dialog similar to the dialogs the KMessageBox convenience functions
33 * create. The main difference is that the KMessageBox methods typically use exec() to show
34 * the dialogs; one of the main disadvantages of using exec(), is that it starts a nested
35 * eventloop, which could lead to nasty crashes.
36 *
37 * Another difference is that the API is supposed to be slightly easier to use as it has
38 * various methods to set up the dialog, e.g. setCaption(), setDetails() ...etc.
39 *
40 * By default, appropriate buttons based on the dialog type are added (since 5.85) (e.g. an
41 * "OK" button is added to an Information dialog), you can set custom buttons by using the
42 * setButtons() method.
43 *
44 * The QDialog::done() slot is called to set the result of the dialog, which will emit the
45 * QDialog::finished() signal with that result. The result is one of the
46 * KMessageDialog::ButtonType enum. This is useful as you can tell exactly which button
47 * was clicked by the user. E.g.:
48 * \list
49 * \li the secondary action button having been clicked, in which case you may still want to save the status
50 * of the "Do not ask again" CheckBox
51 * \li the "Cancel" button having been clicked, in which case you ideally will ignore the status
52 * of the "Do not ask again" CheckBox
53 * \endlist
54 *
55 * For "warning" dialogs, i.e. dialogs with a potentially destructive action, the default
56 * button is set to a button with the QDialogButtonBox::RejectRole. If the "Cancel" button
57 * is used, it will be the default, otherwise the secondary action button.
58 *
59 * This class intends to be very flexible with the buttons that can be used, since you can
60 * call the setButtons() method with a KGuiItem that has custom text/icon.
61 *
62 * Since Frameworks 5.97 a notification sound is played when the dialog opens like KMessageBox
63 * does, this can be controlled using the setNotifyEnabled() method.
64 *
65 * Example:
66 * \code
67 * auto *dlg = new KMessageDialog(KMessageDialog::QuestionTwoActionsCancel,
68 * QStringLiteral("Back or forward?"),
69 * nullptr);
70 *
71 * dlg->setCaption(QStringLiteral("Window Title"));
72 * dlg->setButtons(KStandardGuiItem::back(), KStandardGuiItem::forward(), KStandardGuiItem::cancel());
73 * dlg->setListWidgetItems(QStringList{QStringLiteral("file1"), QStringLiteral("file2")});
74 * dlg->setDetails(QStringLiteral("Some more details."));
75 * dlg->setDontAskAgainText(QStringLiteral("Do not ask again"));
76 * dlg->setDontAskAgainChecked(false);
77 *
78 * // Delete the dialog when it's closed
79 * dlg->setAttribute(Qt::WA_DeleteOnClose);
80 * // Make the dialog window modal
81 * dlg->setWindowModality(Qt::WindowModal);
82 *
83 * QObject::connect(dlg, &QDialog::finished, &app, [dlg](int result) {
84 * auto button = static_cast<KMessageDialog::ButtonType>(result);
85 * switch(button) {
86 * case KMessageDialog::PrimaryAction:
87 * // The user clicked the primary action, handle the result...
88 * // save the "do not ask again" box status...
89 * break;
90 * case KMessageDialog::SecondaryAction:
91 * // The user clicked the secondary action, handle the result...
92 * // save the "do not ask again" box status...
93 * break;
94 * case KMessageDialog::Cancel:
95 * // The user clicked cancel, reject the changes...
96 * break;
97 * default:
98 * break;
99 * }
100 * });
101 *
102 * dlg->show();
103 * \endcode
104 *
105 * \since 5.77
106 */
107class KWIDGETSADDONS_EXPORT KMessageDialog : public QDialog
108{
109 Q_OBJECT
110
111public:
112 /*!
113 * Button types
114 * \since 5.100
115 * \value Ok Ok button
116 * \value Cancel Cancel button
117 * \value PrimaryAction Primary action button
118 * \value SecondaryAction Secondary action button
119 */
120 enum ButtonType {
121 Ok = 1,
122 Cancel = 2,
123 PrimaryAction = 3,
124 SecondaryAction = 4,
125 };
126
127 /*!
128 * \value[since 5.100] QuestionTwoActions Question dialog with two buttons
129 * \value[since 5.100] QuestionTwoActionsCancel Question dialog with two buttons and Cancel
130 * \value[since 5.100] WarningTwoActions Warning dialog with two buttons
131 * \value[since 5.100] WarningTwoActionsCancel Warning dialog with two buttons and Cancel
132 * \value WarningContinueCancel Warning dialog with Continue and Cancel
133 * \value Information Information dialog
134 * \value Error Error dialog
135 */
136 enum Type {
137 QuestionTwoActions = 1,
138 QuestionTwoActionsCancel = 2,
139 WarningTwoActions = 3,
140 WarningTwoActionsCancel = 4,
141 WarningContinueCancel = 5,
142 Information = 6,
143 Error = 8,
144 };
145
146 /*!
147 * Constructs a KMessageDialog.
148 *
149 * Buttons based on the dialog type are set by default in some cases,
150 * using KStandardGuiItem instances. For the dialog types Information and Error
151 * the button is set to KStandardGuiItem::ok(). For the type WarningContinueCancel
152 * the buttons are set to KStandardGuiItem::cont() & KStandardGuiItem::cancel().
153 *
154 * For the other Quesion* and Warning* types the buttons are to be set explicitly.
155 *
156 * \a type the dialog Type, one of KMessageDialog::Type enum
157 *
158 * \a text the text message that is going to be displayed in the dialog
159 *
160 * \a parent a QWidget* that will be set as the dialog parent
161 */
162 explicit KMessageDialog(KMessageDialog::Type type, const QString &text, QWidget *parent = nullptr);
163
164 /*!
165 * This constructor takes the window Id of the parent window, instead of a QWidget*.
166 *
167 * \a type the dialog Type, one of KMessageDialog::Type enum
168 *
169 * \a text the text message that is going to be displayed in the dialog
170 *
171 * \a parent_id the native parent's window system identifier
172 */
173 explicit KMessageDialog(KMessageDialog::Type type, const QString &text, WId parent_id);
174 /*!
175 * Destructor
176 */
177 ~KMessageDialog() override;
178
179 /*!
180 * This can be used to set the title of the dialog window. If you pass an
181 * empty QString(), a generic title will be used depending on the dialog
182 * Type. E.g. for KMessageDialog::WarningTwoActions, "Warning" will be used.
183 */
184 void setCaption(const QString &caption);
185
186 /*!
187 * This can be used to set an icon that will be shown next to the main
188 * text message. If you pass a null QIcon() a generic icon based on the dialog
189 * Type will be used. E.g. for KMessageDialog::QuestionTwoActions, QMessageBox::Question
190 * will be used.
191 */
192 void setIcon(const QIcon &icon);
193
194 /*!
195 * This will add a QListWidget to the dialog and populate it with \a strlist.
196 * If \a strlist is empty, the list widget will not be shown.
197 */
198 void setListWidgetItems(const QStringList &strlist);
199
200 /*!
201 * This will add a KCollapsibleGroupBox with a title "Details", as the class name
202 * implies it is collapsible (and collapsed by default); you can use it to add a
203 * more detailed explanation of what the dialog is trying to tell the user.
204 *
205 * If \a details is empty, the details widget will not be shown.
206 */
207 void setDetails(const QString &details);
208
209 /*!
210 * This will add a "Do not ask again" checkbox to the dialog with the text
211 * from \a dontAskAgainText. You can set the initial status of the checkbox
212 * by using setDontAskAgainChecked().
213 *
214 * If \a dontAskAgainText is empty, no checkbox will be shown.
215 *
216 * Typical usage of this checkbox is for recurring questions, e.g. showing
217 * a dialog to confirm moving files/directories to trash, the user can then
218 * set the checkbox so as not to be asked about that again.
219 *
220 * You can get the state of the checkbox by using isDontAskAgainChecked().
221 */
222 void setDontAskAgainText(const QString &dontAskAgainText);
223
224 /*!
225 * This can be used to set the initial status of the "Do not ask again" checkbox,
226 * checked or unchecked, by setting \a isChecked to \c true or \c false
227 * respectively.
228 *
229 * You need to call setDontAskAgainText() first to actually show a checkbox in
230 * the dialog, otherwise calling this function will have no effect.
231 */
232 void setDontAskAgainChecked(bool isChecked);
233
234 /*!
235 * This can be used to query the status of the "Do not ask again" checkbox;
236 * returns \c true if the box is checked and \c false otherwise.
237 *
238 * \note This method will return \c false if a checkbox widget isn't shown in
239 * the dialog. The dialog will not show a checkbox if setDontAskAgainText() was
240 * not used previously to add a checkbox to begin with.
241 */
242 bool isDontAskAgainChecked() const;
243
244 /*!
245 * Sets the text labels in the dialog to either allow opening external links or not.
246 */
247 void setOpenExternalLinks(bool isAllowed);
248
249 /*!
250 * Whether a KNotification is emitted when the dialog is shown.
251 *
252 * This typically plays a notification sound. Default is true.
253 *
254 * \since 5.97
255 * \sa KMessageBox::Notify
256 */
257 bool isNotifyEnabled() const;
258
259 /*!
260 * Whether to emit a KNotification when the dialog is shown.
261 *
262 * This typically plays a notification sound.
263 *
264 * \since 5.97
265 * \sa KMessageBox::Notify
266 */
267 void setNotifyEnabled(bool enable);
268
269 /*!
270 * Sets the buttons in the buttom box.
271 *
272 * Using this method, you can customize the behavior based on your use-case, by
273 * using a KGuiItem to get a button with custom text and icon.
274 *
275 * Since 5.85 buttons based on the dialog type are added by default (see
276 * KMessageDialog(KMessageDialog::Type, const QString &, QWidget *) for details).
277 * Before, this method had to be called explicitly to have any buttons added to the dialog.
278 *
279 * \note For dialog types Information and Error only one button
280 * (KStandardGuiItem::ok()) is added to the dialog.
281 *
282 * \a primaryAction the action for the primary button.
283 * Reported in the result for dialog types Information and Error
284 * as KMessageDialog::Ok enum value, otherwise as KMessageDialog::PrimaryAction.
285 *
286 * \a secondaryAction the action for the secondary button.
287 * Reported in the result as KMessageDialog::SecondaryAction enum value.
288 * Ignored with all dialog types without a "secondary" action.
289 *
290 * \a cancelAction the action for the cancel button.
291 * Reported in the result as KMessageDialog::Cancel enum value.
292 * Ignored with all dialog types without a Cancel button.
293 */
294 void setButtons(const KGuiItem &primaryAction = KGuiItem(), const KGuiItem &secondaryAction = KGuiItem(), const KGuiItem &cancelAction = KGuiItem());
295
296 /*!
297 * Manually play the notification sound
298 *
299 * When implementing your entirely own message box, not using KMessageDialog,
300 * you can call this function to play the relevant notification sound (if enabled).
301 *
302 * \note You don't need to call this when using KMessageDialog, it plays the sound automatically.
303 *
304 * \a type The message box type
305 *
306 * \a text The message box contents, for accessibility purposes.
307 *
308 * \a dialog The dialog that was displayed
309 *
310 * \since 6.0
311 * \sa setNotifyEnabled
312 */
313 static void beep(KMessageDialog::Type type, const QString &text = QString(), QWidget *dialog = nullptr);
314
315protected:
316 void showEvent(QShowEvent *event) override;
317
318private:
319 std::unique_ptr<KMessageDialogPrivate> const d;
320};
321
322#endif // KMESSAGEDIALOG_H
323

source code of kwidgetsaddons/src/kmessagedialog.h