File indexing completed on 2025-04-27 10:10:25
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "widgetsuntrustedprogramhandler.h" 0009 0010 #include <KIconLoader> 0011 #include <KJobWidgets> 0012 #include <KLocalizedString> 0013 #include <KStandardGuiItem> 0014 0015 #include <QApplication> 0016 #include <QDialog> 0017 #include <QDialogButtonBox> 0018 #include <QHBoxLayout> 0019 #include <QLabel> 0020 #include <QPlainTextEdit> 0021 #include <QPushButton> 0022 #include <QScreen> 0023 #include <QStyle> 0024 #include <QVBoxLayout> 0025 0026 class KIO::WidgetsUntrustedProgramHandlerPrivate 0027 { 0028 public: 0029 QWidget *m_parentWidget = nullptr; 0030 }; 0031 0032 KIO::WidgetsUntrustedProgramHandler::WidgetsUntrustedProgramHandler(QObject *parent) 0033 : KIO::UntrustedProgramHandlerInterface(parent) 0034 , d(std::make_unique<WidgetsUntrustedProgramHandlerPrivate>()) 0035 { 0036 } 0037 0038 KIO::WidgetsUntrustedProgramHandler::~WidgetsUntrustedProgramHandler() 0039 { 0040 } 0041 0042 // Simple QDialog that resizes the given text edit after being shown to more 0043 // or less fit the enclosed text. 0044 class SecureMessageDialog : public QDialog 0045 { 0046 Q_OBJECT 0047 public: 0048 explicit SecureMessageDialog(QWidget *parent) 0049 : QDialog(parent) 0050 , m_textEdit(nullptr) 0051 { 0052 } 0053 0054 void setTextEdit(QPlainTextEdit *textEdit) 0055 { 0056 m_textEdit = textEdit; 0057 } 0058 0059 protected: 0060 void showEvent(QShowEvent *e) override 0061 { 0062 if (e->spontaneous()) { 0063 return; 0064 } 0065 0066 // Now that we're shown, use our width to calculate a good 0067 // bounding box for the text, and resize m_textEdit appropriately. 0068 QDialog::showEvent(e); 0069 0070 if (!m_textEdit) { 0071 return; 0072 } 0073 0074 QSize fudge(20, 24); // About what it sounds like :-/ 0075 0076 // Form rect with a lot of height for bounding. Use no more than 0077 // 5 lines. 0078 QRect curRect(m_textEdit->rect()); 0079 QFontMetrics metrics(fontMetrics()); 0080 curRect.setHeight(5 * metrics.lineSpacing()); 0081 curRect.setWidth(qMax(curRect.width(), 300)); // At least 300 pixels ok? 0082 0083 QString text(m_textEdit->toPlainText()); 0084 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text); 0085 0086 // Scroll bars interfere. If we don't think there's enough room, enable 0087 // the vertical scrollbar however. 0088 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0089 if (curRect.height() < m_textEdit->height()) { // then we've got room 0090 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0091 m_textEdit->setMaximumHeight(curRect.height() + fudge.height()); 0092 } 0093 0094 m_textEdit->setMinimumSize(curRect.size() + fudge); 0095 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); 0096 } 0097 0098 private: 0099 QPlainTextEdit *m_textEdit; 0100 }; 0101 0102 QDialog *KIO::WidgetsUntrustedProgramHandler::createDialog(QWidget *parentWidget, const QString &programName) 0103 { 0104 SecureMessageDialog *baseDialog = new SecureMessageDialog(parentWidget); 0105 baseDialog->setWindowTitle(i18nc("Warning about executing unknown program", "Warning")); 0106 0107 QVBoxLayout *topLayout = new QVBoxLayout(baseDialog); 0108 0109 // Dialog will have explanatory text with a disabled lineedit with the 0110 // Exec= to make it visually distinct. 0111 QWidget *baseWidget = new QWidget(baseDialog); 0112 QHBoxLayout *mainLayout = new QHBoxLayout(baseWidget); 0113 0114 QLabel *iconLabel = new QLabel(baseWidget); 0115 const QIcon icon = baseDialog->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, baseDialog); 0116 const QPixmap warningIcon(icon.pixmap(KIconLoader::SizeHuge)); 0117 mainLayout->addWidget(iconLabel); 0118 iconLabel->setPixmap(warningIcon); 0119 0120 QVBoxLayout *contentLayout = new QVBoxLayout; 0121 QString warningMessage = i18nc("program name follows in a line edit below", "This will start the program:"); 0122 0123 QLabel *message = new QLabel(warningMessage, baseWidget); 0124 contentLayout->addWidget(message); 0125 0126 QPlainTextEdit *textEdit = new QPlainTextEdit(baseWidget); 0127 textEdit->setPlainText(programName); 0128 textEdit->setReadOnly(true); 0129 contentLayout->addWidget(textEdit); 0130 0131 QLabel *footerLabel = new QLabel(i18n("If you do not trust this program, click Cancel")); 0132 contentLayout->addWidget(footerLabel); 0133 contentLayout->addStretch(0); // Don't allow the text edit to expand 0134 0135 mainLayout->addLayout(contentLayout); 0136 0137 topLayout->addWidget(baseWidget); 0138 baseDialog->setTextEdit(textEdit); 0139 0140 QDialogButtonBox *buttonBox = new QDialogButtonBox(baseDialog); 0141 buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0142 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::cont()); 0143 buttonBox->button(QDialogButtonBox::Cancel)->setDefault(true); 0144 buttonBox->button(QDialogButtonBox::Cancel)->setFocus(); 0145 QObject::connect(buttonBox, &QDialogButtonBox::accepted, baseDialog, &QDialog::accept); 0146 QObject::connect(buttonBox, &QDialogButtonBox::rejected, baseDialog, &QDialog::reject); 0147 topLayout->addWidget(buttonBox); 0148 0149 // Constrain maximum size. Minimum size set in 0150 // the dialog's show event. 0151 const QSize screenSize = baseDialog->screen()->size(); 0152 baseDialog->resize(screenSize.width() / 4, 50); 0153 baseDialog->setMaximumHeight(screenSize.height() / 3); 0154 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8); 0155 0156 baseDialog->setAttribute(Qt::WA_DeleteOnClose); 0157 return baseDialog; 0158 } 0159 0160 void KIO::WidgetsUntrustedProgramHandler::showUntrustedProgramWarning(KJob *job, const QString &programName) 0161 { 0162 QWidget *parentWidget = nullptr; 0163 0164 if (job) { 0165 parentWidget = KJobWidgets::window(job); 0166 } 0167 0168 if (!parentWidget) { 0169 parentWidget = d->m_parentWidget; 0170 } 0171 0172 if (!parentWidget) { 0173 parentWidget = qApp->activeWindow(); 0174 } 0175 0176 QDialog *dialog = createDialog(parentWidget, programName); 0177 connect(dialog, &QDialog::accepted, this, [this]() { 0178 Q_EMIT result(true); 0179 }); 0180 connect(dialog, &QDialog::rejected, this, [this]() { 0181 Q_EMIT result(false); 0182 }); 0183 dialog->show(); 0184 } 0185 0186 bool KIO::WidgetsUntrustedProgramHandler::execUntrustedProgramWarning(QWidget *window, const QString &programName) 0187 { 0188 QDialog *dialog = createDialog(window, programName); 0189 return dialog->exec() == QDialog::Accepted; 0190 } 0191 0192 void KIO::WidgetsUntrustedProgramHandler::setWindow(QWidget *window) 0193 { 0194 d->m_parentWidget = window; 0195 } 0196 0197 #include "moc_widgetsuntrustedprogramhandler.cpp" 0198 #include "widgetsuntrustedprogramhandler.moc"