File indexing completed on 2024-05-26 05:37:12

0001 /*
0002     SPDX-FileCopyrightText: 2020 Alexander Lohnau <alexander.lohnau@gmx.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <KConfig>
0008 #include <KConfigGroup>
0009 #include <KLocalizedString>
0010 #include <QDesktopServices>
0011 #include <QDialog>
0012 #include <QDialogButtonBox>
0013 #include <QDir>
0014 #include <QIcon>
0015 #include <QLabel>
0016 #include <QPushButton>
0017 #include <QUrl>
0018 #include <QVBoxLayout>
0019 #include <optional>
0020 struct InstallerInfo {
0021     QString exec;
0022     QString dbusService;
0023     QString desktopFilePath;
0024 };
0025 
0026 class ScriptConfirmationDialog : public QDialog
0027 {
0028 public:
0029     ScriptConfirmationDialog(const QString &installerPath,
0030                              bool install,
0031                              const QString &dir,
0032                              const std::optional<InstallerInfo> &info = std::nullopt,
0033                              QWidget *parent = nullptr)
0034         : QDialog(parent)
0035     {
0036         const auto readmes = QDir(dir).entryList({QStringLiteral("README*")});
0037         setWindowTitle(i18nc("@title:window", "Confirm Installation"));
0038         setWindowIcon(QIcon::fromTheme(QStringLiteral("dialog-information")));
0039         const bool noInstaller = installerPath.isEmpty();
0040         QVBoxLayout *layout = new QVBoxLayout(this);
0041         QString msg;
0042         if (info) {
0043             Q_ASSERT(install); // We do not need the warnings for uninstall
0044             msg = xi18nc("@info", "This plugin executes the following command for starting the \"%1\" service:<nl/>%2", info->dbusService, info->exec);
0045         } else if (!install && noInstaller && readmes.isEmpty()) {
0046             msg = xi18nc("@info",
0047                          "This plugin does not provide an uninstallation script. Please contact the author. "
0048                          "You can try to uninstall the plugin manually.<nl/>"
0049                          "If you do not feel capable or comfortable with this, click <interface>Cancel</interface>  now.");
0050         } else if (!install && noInstaller) {
0051             msg = xi18nc("@info",
0052                          "This plugin does not provide an uninstallation script. Please contact the author. "
0053                          "You can try to uninstall the plugin manually. Please have a look at the README "
0054                          "for instructions from the author.<nl/>"
0055                          "If you do not feel capable or comfortable with this, click <interface>Cancel</interface>  now.");
0056         } else if (noInstaller && readmes.isEmpty()) {
0057             msg = xi18nc("@info",
0058                          "This plugin does not provide an installation script. Please contact the author. "
0059                          "You can try to install the plugin manually.<nl/>"
0060                          "If you do not feel capable or comfortable with this, click <interface>Cancel</interface>  now.");
0061         } else if (noInstaller) {
0062             msg = xi18nc("@info",
0063                          "This plugin does not provide an installation script. Please contact the author. "
0064                          "You can try to install the plugin manually. Please have a look at the README "
0065                          "for instructions from the author.<nl/>"
0066                          "If you do not feel capable or comfortable with this, click <interface>Cancel</interface>  now.");
0067         } else if (readmes.isEmpty()) {
0068             msg = xi18nc("@info",
0069                          "This plugin uses a script for installation which can pose a security risk. "
0070                          "Please examine the entire plugin's contents before installing, or at least "
0071                          "read the script's source code.<nl/>"
0072                          "If you do not feel capable or comfortable with this, click <interface>Cancel</interface>  now.");
0073         } else {
0074             msg = xi18nc("@info",
0075                          "This plugin uses a script for installation which can pose a security risk. "
0076                          "Please examine the entire plugin's contents before installing, or at least "
0077                          "read the README file and the script's source code.<nl/>"
0078                          "If you do not feel capable or comfortable with this, click <interface>Cancel</interface>  now.");
0079         }
0080         QLabel *msgLabel = new QLabel(msg, this);
0081         msgLabel->setWordWrap(true);
0082         layout->addWidget(msgLabel);
0083         auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0084         buttonBox->button(QDialogButtonBox::Ok)->setIcon(QIcon::fromTheme("emblem-warning"));
0085         connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0086         connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0087 
0088         QString okText;
0089         if (noInstaller && !install && !info) {
0090             okText = i18nc("@action:button", "Mark entry as uninstalled");
0091         } else if (noInstaller && !info) {
0092             okText = i18nc("@action:button", "Mark entry as installed");
0093         } else {
0094             okText = i18nc("@action:button", "Accept Risk And Continue");
0095         }
0096         buttonBox->button(QDialogButtonBox::Ok)->setText(okText);
0097 
0098         QHBoxLayout *helpButtonLayout = new QHBoxLayout(this);
0099         if (!noInstaller) {
0100             QPushButton *scriptButton = new QPushButton(QIcon::fromTheme("dialog-scripts"), i18nc("@action:button", "View Script"), this);
0101             connect(scriptButton, &QPushButton::clicked, this, [installerPath]() {
0102                 QDesktopServices::openUrl(QUrl::fromLocalFile(installerPath));
0103             });
0104             helpButtonLayout->addWidget(scriptButton);
0105         }
0106         QPushButton *sourceButton = new QPushButton(QIcon::fromTheme("document-open-folder"), i18nc("@action:button", "View Source Directory"), this);
0107         connect(sourceButton, &QPushButton::clicked, this, [dir]() {
0108             QDesktopServices::openUrl(QUrl::fromLocalFile(dir));
0109         });
0110         if (readmes.isEmpty() && helpButtonLayout->isEmpty()) {
0111             // If there is no script and readme we can display the button in the same line
0112             buttonBox->addButton(sourceButton, QDialogButtonBox::HelpRole);
0113         } else {
0114             helpButtonLayout->addWidget(sourceButton);
0115         }
0116         if (!readmes.isEmpty()) {
0117             QPushButton *readmeButton = new QPushButton(QIcon::fromTheme("text-x-readme"), i18nc("@action:button", "View %1", readmes.at(0)), this);
0118             connect(readmeButton, &QPushButton::clicked, this, [dir, readmes]() {
0119                 QDesktopServices::openUrl(QUrl::fromLocalFile(QDir(dir).absoluteFilePath(readmes.at(0))));
0120             });
0121             helpButtonLayout->addWidget(readmeButton);
0122         }
0123         helpButtonLayout->setAlignment(Qt::AlignRight);
0124         layout->addLayout(helpButtonLayout);
0125         buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
0126         layout->addWidget(buttonBox);
0127     }
0128 };