File indexing completed on 2024-04-14 11:09:26

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
0004     SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2006, 2007 Kevin Ottens <ervin@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "kdialogjobuidelegate.h"
0011 
0012 #include <QPointer>
0013 #include <QQueue>
0014 #include <QWidget>
0015 
0016 #include <KJob>
0017 #include <KMessageBox>
0018 #include <kjobwidgets.h>
0019 
0020 #include <config-kjobwidgets.h>
0021 #if HAVE_X11
0022 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0023 #include <private/qtx11extras_p.h>
0024 #else
0025 #include <QX11Info>
0026 #endif
0027 #endif
0028 
0029 enum DialogType { ErrorDialog, WarningDialog };
0030 
0031 struct MessageBoxData {
0032     QWidget *widget;
0033     DialogType type = ErrorDialog;
0034     QString msg;
0035 };
0036 
0037 class KDialogJobUiDelegatePrivate : public QObject
0038 {
0039     Q_OBJECT
0040 public:
0041     explicit KDialogJobUiDelegatePrivate(QObject *parent = nullptr);
0042     ~KDialogJobUiDelegatePrivate() override;
0043     void queuedMessageBox(QWidget *widget, DialogType type, const QString &msg);
0044 
0045     QWidget *window;
0046 
0047 public Q_SLOTS:
0048     void next();
0049 
0050 private:
0051     bool running;
0052     QQueue<QSharedPointer<MessageBoxData>> queue;
0053 };
0054 
0055 KDialogJobUiDelegatePrivate::KDialogJobUiDelegatePrivate(QObject *parent)
0056     : QObject(parent)
0057     , window(nullptr)
0058     , running(false)
0059 {
0060 }
0061 
0062 KDialogJobUiDelegatePrivate::~KDialogJobUiDelegatePrivate()
0063 {
0064     queue.clear();
0065 }
0066 
0067 void KDialogJobUiDelegatePrivate::next()
0068 {
0069     if (queue.isEmpty()) {
0070         running = false;
0071         return;
0072     }
0073 
0074     QSharedPointer<MessageBoxData> data = queue.dequeue();
0075 
0076     // kmessagebox starts a new event loop which can cause this to get deleted
0077     // https://bugs.kde.org/show_bug.cgi?id=356321#c16
0078     QPointer<KDialogJobUiDelegatePrivate> thisGuard(this);
0079 
0080     switch (data->type) {
0081     case ErrorDialog:
0082         KMessageBox::error(data->widget, data->msg);
0083         break;
0084     case WarningDialog:
0085         KMessageBox::information(data->widget, data->msg);
0086         break;
0087     };
0088 
0089     if (!thisGuard) {
0090         return;
0091     }
0092 
0093     QMetaObject::invokeMethod(this, &KDialogJobUiDelegatePrivate::next, Qt::QueuedConnection);
0094 }
0095 
0096 void KDialogJobUiDelegatePrivate::queuedMessageBox(QWidget *widget, DialogType type, const QString &msg)
0097 {
0098     QSharedPointer<MessageBoxData> data(new MessageBoxData{widget, type, msg});
0099 
0100     queue.enqueue(data);
0101 
0102     if (!running) {
0103         running = true;
0104         QMetaObject::invokeMethod(this, &KDialogJobUiDelegatePrivate::next, Qt::QueuedConnection);
0105     }
0106 }
0107 
0108 KDialogJobUiDelegate::KDialogJobUiDelegate()
0109     : KJobUiDelegate()
0110     , d(new KDialogJobUiDelegatePrivate)
0111 {
0112 }
0113 
0114 KDialogJobUiDelegate::KDialogJobUiDelegate(KJobUiDelegate::Flags flags, QWidget *window)
0115     : KJobUiDelegate(flags)
0116     , d(new KDialogJobUiDelegatePrivate)
0117 {
0118     d->window = window;
0119 }
0120 
0121 KDialogJobUiDelegate::~KDialogJobUiDelegate() = default;
0122 
0123 bool KDialogJobUiDelegate::setJob(KJob *job)
0124 {
0125     bool ret = KJobUiDelegate::setJob(job);
0126 #if HAVE_X11
0127     if (ret) {
0128         unsigned long time = QX11Info::appUserTime();
0129         KJobWidgets::updateUserTimestamp(job, time);
0130     }
0131 #endif
0132     return ret;
0133 }
0134 
0135 void KDialogJobUiDelegate::setWindow(QWidget *window)
0136 {
0137     if (job()) {
0138         KJobWidgets::setWindow(job(), window);
0139     }
0140     d->window = window;
0141 }
0142 
0143 QWidget *KDialogJobUiDelegate::window() const
0144 {
0145     if (d->window) {
0146         return d->window;
0147     } else if (job()) {
0148         return KJobWidgets::window(job());
0149     }
0150     return nullptr;
0151 }
0152 
0153 void KDialogJobUiDelegate::updateUserTimestamp(unsigned long time)
0154 {
0155     KJobWidgets::updateUserTimestamp(job(), time);
0156 }
0157 
0158 unsigned long KDialogJobUiDelegate::userTimestamp() const
0159 {
0160     return KJobWidgets::userTimestamp(job());
0161 }
0162 
0163 void KDialogJobUiDelegate::showErrorMessage()
0164 {
0165     if (job()->error() != KJob::KilledJobError) {
0166         d->queuedMessageBox(window(), ErrorDialog, job()->errorString());
0167     }
0168 }
0169 
0170 void KDialogJobUiDelegate::slotWarning(KJob * /*job*/, const QString &plain, const QString & /*rich*/)
0171 {
0172     if (isAutoWarningHandlingEnabled()) {
0173         d->queuedMessageBox(window(), WarningDialog, plain);
0174     }
0175 }
0176 
0177 #include "kdialogjobuidelegate.moc"
0178 #include "moc_kdialogjobuidelegate.cpp"