KIO

widgetsuntrustedprogramhandler.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "widgetsuntrustedprogramhandler.h"
9
10#include <KIconLoader>
11#include <KJob>
12#include <KJobWidgets>
13#include <KLocalizedString>
14#include <KMessageDialog>
15#include <KStandardGuiItem>
16
17#include <QApplication>
18#include <QDialog>
19#include <QDialogButtonBox>
20#include <QHBoxLayout>
21#include <QLabel>
22#include <QPlainTextEdit>
23#include <QPushButton>
24#include <QScreen>
25#include <QStyle>
26#include <QVBoxLayout>
27
28class KIO::WidgetsUntrustedProgramHandlerPrivate
29{
30public:
31 QWidget *m_parentWidget = nullptr;
32};
33
34KIO::WidgetsUntrustedProgramHandler::WidgetsUntrustedProgramHandler(QObject *parent)
35 : KIO::UntrustedProgramHandlerInterface(parent)
36 , d(std::make_unique<WidgetsUntrustedProgramHandlerPrivate>())
37{
38}
39
40KIO::WidgetsUntrustedProgramHandler::~WidgetsUntrustedProgramHandler()
41{
42}
43
44// Simple QDialog that resizes the given text edit after being shown to more
45// or less fit the enclosed text.
46class SecureMessageDialog : public QDialog
47{
48 Q_OBJECT
49public:
50 explicit SecureMessageDialog(QWidget *parent)
51 : QDialog(parent)
52 , m_textEdit(nullptr)
53 {
54 }
55
56 void setTextEdit(QPlainTextEdit *textEdit)
57 {
58 m_textEdit = textEdit;
59 }
60
61protected:
62 void showEvent(QShowEvent *e) override
63 {
64 if (e->spontaneous()) {
65 return;
66 }
67
68 // Now that we're shown, use our width to calculate a good
69 // bounding box for the text, and resize m_textEdit appropriately.
71
72 if (!m_textEdit) {
73 return;
74 }
75
76 QSize fudge(20, 24); // About what it sounds like :-/
77
78 // Form rect with a lot of height for bounding. Use no more than
79 // 5 lines.
80 QRect curRect(m_textEdit->rect());
81 QFontMetrics metrics(fontMetrics());
82 curRect.setHeight(5 * metrics.lineSpacing());
83 curRect.setWidth(qMax(curRect.width(), 300)); // At least 300 pixels ok?
84
85 QString text(m_textEdit->toPlainText());
86 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
87
88 // Scroll bars interfere. If we don't think there's enough room, enable
89 // the vertical scrollbar however.
90 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
91 if (curRect.height() < m_textEdit->height()) { // then we've got room
92 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
93 m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
94 }
95
96 m_textEdit->setMinimumSize(curRect.size() + fudge);
97 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
98
99 // Mimicks a message box
101 }
102
103private:
104 QPlainTextEdit *m_textEdit;
105};
106
107QDialog *KIO::WidgetsUntrustedProgramHandler::createDialog(QWidget *parentWidget, const QString &programName)
108{
109 SecureMessageDialog *baseDialog = new SecureMessageDialog(parentWidget);
110 baseDialog->setWindowTitle(i18nc("Warning about executing unknown program", "Warning"));
111
112 QVBoxLayout *topLayout = new QVBoxLayout(baseDialog);
113
114 // Dialog will have explanatory text with a disabled lineedit with the
115 // Exec= to make it visually distinct.
116 QWidget *baseWidget = new QWidget(baseDialog);
117 QHBoxLayout *mainLayout = new QHBoxLayout(baseWidget);
118
119 QLabel *iconLabel = new QLabel(baseWidget);
120 const QIcon icon = baseDialog->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, baseDialog);
121 const QPixmap warningIcon(icon.pixmap(KIconLoader::SizeHuge));
122 mainLayout->addWidget(iconLabel);
123 iconLabel->setPixmap(warningIcon);
124
125 QVBoxLayout *contentLayout = new QVBoxLayout;
126 QString warningMessage = i18nc("program name follows in a line edit below", "This will start the program:");
127
128 QLabel *message = new QLabel(warningMessage, baseWidget);
129 contentLayout->addWidget(message);
130
131 QPlainTextEdit *textEdit = new QPlainTextEdit(baseWidget);
132 textEdit->setPlainText(programName);
133 textEdit->setReadOnly(true);
134 contentLayout->addWidget(textEdit);
135
136 QLabel *footerLabel = new QLabel(i18n("If you do not trust this program, click Cancel"));
137 contentLayout->addWidget(footerLabel);
138 contentLayout->addStretch(0); // Don't allow the text edit to expand
139
140 mainLayout->addLayout(contentLayout);
141
142 topLayout->addWidget(baseWidget);
143 baseDialog->setTextEdit(textEdit);
144
145 QDialogButtonBox *buttonBox = new QDialogButtonBox(baseDialog);
148 buttonBox->button(QDialogButtonBox::Cancel)->setDefault(true);
152 topLayout->addWidget(buttonBox);
153
154 // Constrain maximum size. Minimum size set in
155 // the dialog's show event.
156 const QSize screenSize = baseDialog->screen()->size();
157 baseDialog->resize(screenSize.width() / 4, 50);
158 baseDialog->setMaximumHeight(screenSize.height() / 3);
159 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
160
162 return baseDialog;
163}
164
165void KIO::WidgetsUntrustedProgramHandler::showUntrustedProgramWarning(KJob *job, const QString &programName)
166{
167 QWidget *parentWidget = nullptr;
168
169 if (job) {
170 parentWidget = KJobWidgets::window(job);
171 }
172
173 if (!parentWidget) {
174 parentWidget = d->m_parentWidget;
175 }
176
177 if (!parentWidget) {
178 parentWidget = qApp->activeWindow();
179 }
180
181 QDialog *dialog = createDialog(parentWidget, programName);
182 connect(dialog, &QDialog::accepted, this, [this]() {
183 Q_EMIT result(true);
184 });
185 connect(dialog, &QDialog::rejected, this, [this]() {
186 Q_EMIT result(false);
187 });
188 dialog->show();
189}
190
191bool KIO::WidgetsUntrustedProgramHandler::execUntrustedProgramWarning(QWidget *window, const QString &programName)
192{
193 QDialog *dialog = createDialog(window, programName);
194 return dialog->exec() == QDialog::Accepted;
195}
196
197void KIO::WidgetsUntrustedProgramHandler::setWindow(QWidget *window)
198{
199 d->m_parentWidget = window;
200}
201
202#include "moc_widgetsuntrustedprogramhandler.cpp"
203#include "widgetsuntrustedprogramhandler.moc"
static void assign(QPushButton *button, const KGuiItem &item)
static void beep(KMessageDialog::Type type, const QString &text=QString(), QWidget *dialog=nullptr)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
A namespace for KIO globals.
QWidget * window(QObject *job)
KGuiItem cont()
void addLayout(QLayout *layout, int stretch)
void addStretch(int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void accept()
void accepted()
virtual int exec()
virtual void reject()
void rejected()
virtual void showEvent(QShowEvent *event) override
QPushButton * button(StandardButton which) const const
void setStandardButtons(StandardButtons buttons)
bool spontaneous() const const
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
void setPixmap(const QPixmap &)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void setReadOnly(bool ro)
void setPlainText(const QString &text)
void setDefault(bool)
int height() const const
int width() const const
SP_MessageBoxWarning
virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const const=0
ScrollBarAlwaysOff
TextWordWrap
WA_DeleteOnClose
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setMaximumHeight(int maxh)
void setMaximumWidth(int maxw)
QScreen * screen() const const
void setAttribute(Qt::WidgetAttribute attribute, bool on)
void setFocus()
void show()
void resize(const QSize &)
QStyle * style() const const
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri May 2 2025 12:02:24 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.