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