File indexing completed on 2024-04-28 15:32:06

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2020 Ahmad Samir <a.samirh78@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #ifndef KMESSAGEDIALOG_H
0009 #define KMESSAGEDIALOG_H
0010 
0011 #include <kwidgetsaddons_export.h>
0012 
0013 #include <KStandardGuiItem>
0014 
0015 #include <QDialog>
0016 #include <QDialogButtonBox>
0017 #include <QMessageBox>
0018 
0019 #include <memory>
0020 
0021 class KMessageDialogPrivate;
0022 class KGuiItem;
0023 
0024 /**
0025  * @class KMessageDialog kmessagedialog.h <KMessageDialog>
0026  *
0027  *
0028  * @brief KMessageDialog creates a message box similar to the ones you get from KMessageBox,
0029  * but that can be used asynchronously, i.e. you can show the dialog by using @c show()
0030  * or @c open().
0031  *
0032  * This class contructs a dialog similar to the dialogs the KMessageBox convenience functions
0033  * create. The main difference is that the KMessageBox methods typically use @c exec() to show
0034  * the dialogs; one of the main disadvantages of using @c exec(), is that it starts a nested
0035  * eventloop, which could lead to nasty crashes.
0036  *
0037  * Another difference is that the API is supposed to be slightly easier to use as it has
0038  * various methods to set up the dialog, e.g. @ref setCaption(), @ref setDetails() ...etc.
0039  *
0040  * By default, appropriate buttons based on the dialog type are added (since 5.85) (e.g. an
0041  * "OK" button is added to an Information dialog), you can set custom buttons by using the
0042  * @ref setButtons() method.
0043  *
0044  * The @ref QDialog::done() slot is called to set the result of the dialog, which will emit the
0045  * @ref QDialog::finished() signal with that result. The result is one of the
0046  * KMessageDialog::ButtonType enum. This is useful as you can tell exactly which button
0047  * was clicked by the user. E.g.:
0048  * - the secondary action button having been clicked, in which case you may still want to save the status
0049  *   of the "Do not ask again" CheckBox
0050  * - the "Cancel" button having been clicked, in which case you ideally will ignore the status
0051  *   of the "Do not ask again" CheckBox
0052  *
0053  * For "warning" dialogs, i.e. dialogs with a potentially destructive action, the default
0054  * button is set to a button with the QDialogButtonBox::RejectRole. If the "Cancel" button
0055 + * is used, it will be the default, otherwise the secondary action button.
0056  *
0057  * This class intends to be very flexible with the buttons that can be used, since you can
0058  * call the @ref setButtons() method with a KGuiItem that has custom text/icon.
0059  *
0060  * Since Frameworks 5.97 a notification sound is played when the dialog opens like KMessageBox
0061  * does, this can be controlled using the @ref setNotifyEnabled() method.
0062  *
0063  * Example:
0064  * @code
0065  * auto *dlg = new KMessageDialog(KMessageDialog::QuestionTwoActionsCancel,
0066  *                                QStringLiteral("Back or forward?"),
0067  *                                nullptr);
0068  *
0069  * dlg->setCaption(QStringLiteral("Window Title"));
0070  * dlg->setButtons(KStandardGuiItem::back(), KStandardGuiItem::forward(), KStandardGuiItem::cancel());
0071  * dlg->setListWidgetItems(QStringList{QStringLiteral("file1"), QStringLiteral("file2")});
0072  * dlg->setDetails(QStringLiteral("Some more details."));
0073  * dlg->setDontAskAgainText(QStringLiteral("Do not ask again"));
0074  * dlg->setDontAskAgainChecked(false);
0075  *
0076  *  // Delete the dialog when it's closed
0077  *  dlg->setAttribute(Qt::WA_DeleteOnClose);
0078  *  // Make the dialog window modal
0079  *  dlg->setWindowModality(Qt::WindowModal);
0080  *
0081  *  QObject::connect(dlg, &QDialog::finished, &app, [dlg](int result) {
0082  *      auto button = static_cast<KMessageDialog::ButtonType>(result);
0083  *      switch(button) {
0084  *      case KMessageDialog::Ok:
0085  *      case KMessageDialog::PrimaryAction:
0086  *          // The user clicked the primary action, handle the result...
0087  *          // save the "do not ask again" box status...
0088  *          break;
0089  *      case KMessageDialog::SecondaryAction:
0090  *          // The user clicked the secondary action, handle the result...
0091  *          // save the "do not ask again" box status...
0092  *          break;
0093  *      case KMessageDialog::Cancel:
0094  *          // The user clicked cancel, reject the changes...
0095  *          break;
0096  *      default:
0097  *          break;
0098  *      }
0099  *  });
0100  *
0101  *  dlg->show();
0102  * @endcode
0103  *
0104  * @since 5.77
0105  */
0106 
0107 class KWIDGETSADDONS_EXPORT KMessageDialog : public QDialog
0108 {
0109     Q_OBJECT
0110 
0111 public:
0112     /**
0113      * Button types
0114      * @since 5.100
0115      */
0116     enum ButtonType {
0117         /// For backward-compatibility with KF < 5.100 only, use @c QDialogButtonBox::Ok.
0118         Ok = QDialogButtonBox::Ok,
0119         /// For backward-compatibility with KF < 5.100 only, use @c QDialogButtonBox::Cancel.
0120         Cancel = QDialogButtonBox::Cancel,
0121         /// For backward-compatibility with KF < 5.100 only, use @c QDialogButtonBox::Yes.
0122         PrimaryAction = QDialogButtonBox::Yes,
0123         /// For backward-compatibility with KF < 5.100 only, use @c QDialogButtonBox::No.
0124         SecondaryAction = QDialogButtonBox::No,
0125     };
0126 
0127     enum Type {
0128         QuestionTwoActions = 1, ///< @since 5.100
0129         QuestionTwoActionsCancel = 2, ///< @since 5.100
0130         WarningTwoActions = 3, ///< @since 5.100
0131         WarningTwoActionsCancel = 4, ///< @since 5.100
0132         WarningContinueCancel = 5,
0133         Information = 6,
0134 #if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(5, 97)
0135         Sorry ///< @deprecated Since 5.97, use Error.
0136             KWIDGETSADDONS_ENUMERATOR_DEPRECATED_VERSION(5, 97, "Use Error.") = 7,
0137 #endif
0138         Error = 8,
0139 #if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(5, 100)
0140         /// @deprecated Since 5.100, use QuestionTwoActions.
0141         QuestionYesNo KWIDGETSADDONS_ENUMERATOR_DEPRECATED_VERSION(5, 100, "Use QuestionTwoActions.") = QuestionTwoActions,
0142         /// @deprecated Since 5.100, use QuestionTwoActionsCancel.
0143         QuestionYesNoCancel KWIDGETSADDONS_ENUMERATOR_DEPRECATED_VERSION(5, 100, "Use QuestionTwoActionsCancel.") = QuestionTwoActionsCancel,
0144         /// @deprecated Since 5.100, use WarningTwoActions.
0145         WarningYesNo KWIDGETSADDONS_ENUMERATOR_DEPRECATED_VERSION(5, 100, "Use WarningTwoActions.") = WarningTwoActions,
0146         /// @deprecated Since 5.100, use WarningTwoActionsCancel.
0147         WarningYesNoCancel KWIDGETSADDONS_ENUMERATOR_DEPRECATED_VERSION(5, 100, "Use WarningTwoActionsCancel.") = WarningTwoActionsCancel,
0148 #endif
0149     };
0150 
0151     /**
0152      * Constructs a KMessageDialog.
0153      *
0154      * Since 5.85 buttons based on the dialog type are set by default in some cases,
0155      * using KStandardGuiItem instances. For the dialog types Information, Sorry & Error
0156      * the button is set to KStandardGuiItem::ok(). For the type WarningContinueCancel
0157      * the buttons are set to  KStandardGuiItem::cont() & KStandardGuiItem::cancel().
0158      *
0159      * For the other Quesion* and Warning* types the buttons are to be set explicitly.
0160      * Since 5.85 and if KWidgetsAddons is built with support for deprecated API including 5.100,
0161      * also for these types the buttons are set by default, using KStandardGuiItem instances.
0162      * - QuestionTwoActions: KStandardGuiItem::yes(), KStandardGuiItem::no()
0163      * - QuestionTwoActionsCancel:  KStandardGuiItem::yes(), KStandardGuiItem::no()
0164      * - WarningTwoActions:  KStandardGuiItem::yes(), KStandardGuiItem::no()
0165      * - WarningTwoActionsCancel:  KStandardGuiItem::yes(), KStandardGuiItem::no()
0166      *
0167      * @param type the dialog Type, one of KMessageDialog::Type enum
0168      * @param text the text message that is going to be displayed in the dialog
0169      * @param parent a QWidget* that will be set as the dialog parent
0170      */
0171     explicit KMessageDialog(KMessageDialog::Type type, const QString &text, QWidget *parent = nullptr);
0172 
0173     /**
0174      * This constructor takes the window Id of the parent window, instead of a QWidget*.
0175      *
0176      * @param type the dialog Type, one of KMessageDialog::Type enum
0177      * @param text the text message that is going to be displayed in the dialog
0178      * @param parent_id the native parent's window system identifier
0179      */
0180     explicit KMessageDialog(KMessageDialog::Type type, const QString &text, WId parent_id);
0181     /**
0182      * Destructor
0183      */
0184     ~KMessageDialog() override;
0185 
0186     /**
0187      * This can be used to set the title of the dialog window. If you pass an
0188      * empty QString(), a generic title will be used depending on the dialog
0189      * Type. E.g. for KMessageDialog::WarningTwoActions, "Warning" will be used.
0190      */
0191     void setCaption(const QString &caption);
0192 
0193     /**
0194      * This can be used to set an icon that will be shown next to the main
0195      * text message. If you pass a null QIcon() a generic icon based on the dialog
0196      * Type will be used. E.g. for KMessageDialog::QuestionTwoActions, QMessageBox::Question
0197      * will be used.
0198      */
0199     void setIcon(const QIcon &icon);
0200 
0201     /**
0202      * This will add a QListWidget to the dialog and populate it with @p strlist.
0203      * If @p strlist is empty, the list widget will not be shown.
0204      */
0205     void setListWidgetItems(const QStringList &strlist);
0206 
0207     /**
0208      * This will add a KCollapsibleGroupBox with a title "Details", as the class name
0209      * implies it is collapsible (and collapsed by default); you can use it to add a
0210      * more detailed explanation of what the dialog is trying to tell the user.
0211      *
0212      * If @p details is empty, the details widget will not be shown.
0213      */
0214     void setDetails(const QString &details);
0215 
0216     /**
0217      * This will add a "Do not ask again" checkbox to the dialog with the text
0218      * from @p dontAskAgainText. You can set the initial status of the checkbox
0219      * by using setDontAskAgainChecked().
0220      *
0221      * If @p dontAskAgainText is empty, no checkbox will be shown.
0222      *
0223      * Typical usage of this checkbox is for recurring questions, e.g. showing
0224      * a dialog to confirm moving files/directories to trash, the user can then
0225      * set the checkbox so as not to be asked about that again.
0226      *
0227      * You can get the state of the checkbox by using isDontAskAgainChecked().
0228      */
0229     void setDontAskAgainText(const QString &dontAskAgainText);
0230 
0231     /**
0232      * This can be used to set the initial status of the "Do not ask again" checkbox,
0233      * checked or unchecked, by setting @p isChecked to @c true or @c false
0234      * respectively.
0235      *
0236      * You need to call setDontAskAgainText() first to actually show a checkbox in
0237      * the dialog, otherwise calling this function will have no effect.
0238      */
0239     void setDontAskAgainChecked(bool isChecked);
0240 
0241     /**
0242      * This can be used to query the status of the "Do not ask again" checkbox;
0243      * returns @c true if the box is checked and @c false otherwise.
0244      *
0245      * @note This method will return @c false if a checkbox widget isn't shown in
0246      * the dialog. The dialog will not show a checkbox if setDontAskAgainText() was
0247      * not used previously to add a checkbox to begin with.
0248      */
0249     bool isDontAskAgainChecked() const;
0250 
0251     /**
0252      * Sets the text labels in the dialog to either allow opening external links or not.
0253      */
0254     void setOpenExternalLinks(bool isAllowed);
0255 
0256     /**
0257      * Whether a KNotification is emitted when the dialog is shown.
0258      *
0259      * This typically plays a notification sound. Default is true.
0260      *
0261      * @since 5.97
0262      * @sa KMessageBox::Notify
0263      */
0264     bool isNotifyEnabled() const;
0265 
0266     /**
0267      * Whether to emit a KNotification when the dialog is shown.
0268      *
0269      * This typically plays a notification sound.
0270      *
0271      * @since 5.97
0272      * @sa KMessageBox::Notify
0273      */
0274     void setNotifyEnabled(bool enable);
0275 
0276     /**
0277      * Sets the buttons in the buttom box.
0278      *
0279      * Using this method, you can customize the behavior based on your use-case, by
0280      * using a KGuiItem to get a button with custom text and icon.
0281      *
0282      * Since 5.85 buttons based on the dialog type are added by default (see
0283      * KMessageDialog(KMessageDialog::Type, const QString &, QWidget *) for details).
0284      * Before, this method had to be called explicitly to have any buttons added to the dialog.
0285      *
0286      * @note
0287      * - For WarningContinueCancel dialog Type, if primaryAction has the same text as
0288      *   KStandardGuiItem::yes(), KStandardGuiItem::cont() will be used instead (as long
0289      *   as KWidgetsAddons is built with the deprecated KStandardGuiItem::yes()).
0290      * - For dialog types Information, Sorry, and Error only one button
0291      *   (KStandardGuiItem::ok()) is added to the dialog.
0292      *
0293      * @param primaryAction the action for the primary button.
0294      *                      Reported in the result for dialog types Information, Sorry, and Error
0295      *                      as KMessageDialog::Ok enum value, otherwise as KMessageDialog::PrimaryAction.
0296      * @param secondaryAction the action for the secondary button.
0297      *                        Reported in the result as KMessageDialog::SecondaryAction enum value.
0298      *                        Ignored with all dialog types without a "secondary" action.
0299      * @param cancelAction the action for the cancel button.
0300      *                     Reported in the result as KMessageDialog::Cancel enum value.
0301      *                     Ignored with all dialog types without a Cancel button.
0302      */
0303 #if KWIDGETSADDONS_ENABLE_DEPRECATED_SINCE(5, 100)
0304     void setButtons(const KGuiItem &primaryAction = KStandardGuiItem::yes(),
0305                     const KGuiItem &secondaryAction = KStandardGuiItem::no(),
0306                     const KGuiItem &cancelAction = KStandardGuiItem::cancel());
0307 #else
0308     void setButtons(const KGuiItem &primaryAction = KGuiItem(), const KGuiItem &secondaryAction = KGuiItem(), const KGuiItem &cancelAction = KGuiItem());
0309 #endif
0310 
0311 private:
0312     std::unique_ptr<KMessageDialogPrivate> const d;
0313 };
0314 
0315 #endif // KMESSAGEDIALOG_H