┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src/dolphinpackageinstaller.cpp
blob: b70159663d2be3f0a64cf4151565e970b50d4382 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
    This file is part of the KDE project
    SPDX-FileCopyrightText: 2024 Felix Ernst <[email protected]>

    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/

#include "dolphinpackageinstaller.h"

#include <KLocalizedString>

#if HAVE_PACKAGEKIT
#include <PackageKit/Daemon>
#else
#include <QDesktopServices>
#endif

#include <QTimer>
#include <QtAssert>

DolphinPackageInstaller::DolphinPackageInstaller(const QString &packageName,
                                                 const QUrl &fallBackInstallationPageUrl,
                                                 std::function<bool()> isPackageInstalledCheck,
                                                 QObject *parent)
    : KJob(parent)
    , m_packageName{packageName}
    , m_fallBackInstallationPageUrl{fallBackInstallationPageUrl}
    , m_isPackageInstalledCheck{isPackageInstalledCheck}
{
}

void DolphinPackageInstaller::start()
{
    if (m_isPackageInstalledCheck()) {
        emitResult();
        return;
    }

#if HAVE_PACKAGEKIT
    PackageKit::Daemon::setHints(PackageKit::Daemon::hints() + QStringList{QStringLiteral("interactive=true")});
    const PackageKit::Transaction *resolveTransaction = PackageKit::Daemon::resolve(m_packageName);

    connect(resolveTransaction, &PackageKit::Transaction::errorCode, this, &DolphinPackageInstaller::slotInstallationFailed);
    connect(resolveTransaction, &PackageKit::Transaction::finished, this, [this]() { // Will be disconnected if we find a package.
        slotInstallationFailed(PackageKit::Transaction::ErrorPackageNotFound,
                               i18nc("@info:shell about system packages", "Could not find package %1.", m_packageName));
    });
    connect(resolveTransaction,
            &PackageKit::Transaction::package,
            this,
            [this, resolveTransaction](PackageKit::Transaction::Info /* info */, const QString &packageId) {
                disconnect(resolveTransaction, nullptr, this, nullptr); // We only care about the first package.
                install(packageId);
            });
#else
    QDesktopServices::openUrl(m_fallBackInstallationPageUrl);
    auto waitForSuccess = new QTimer(this);
    connect(waitForSuccess, &QTimer::timeout, this, [this]() {
        if (m_isPackageInstalledCheck()) {
            emitResult();
        }
    });
    waitForSuccess->start(3000);
#endif
}

#if HAVE_PACKAGEKIT
void DolphinPackageInstaller::install(const QString &packageId)
{
    const PackageKit::Transaction *installTransaction = PackageKit::Daemon::installPackage(packageId);
    connectTransactionToJobProgress(*installTransaction);
    connect(installTransaction,
            &PackageKit::Transaction::errorCode,
            this,
            [installTransaction, this](PackageKit::Transaction::Error error, const QString &details) {
                disconnect(installTransaction, nullptr, this, nullptr); // We only want to emit a result once.
                slotInstallationFailed(error, details);
            });
    connect(installTransaction,
            &PackageKit::Transaction::finished,
            this,
            [installTransaction, this](const PackageKit::Transaction::Exit status, uint /* runtime */) {
                disconnect(installTransaction, nullptr, this, nullptr); // We only want to emit a result once.
                if (status == PackageKit::Transaction::ExitSuccess) {
                    emitResult();
                } else {
                    slotInstallationFailed(PackageKit::Transaction::ErrorUnknown,
                                           i18nc("@info %1 is error code",
                                                 "Installation exited without reporting success. (%1)",
                                                 QMetaEnum::fromType<PackageKit::Transaction::Exit>().valueToKey(status)));
                }
            });
}

void DolphinPackageInstaller::connectTransactionToJobProgress(const PackageKit::Transaction &transaction)
{
    connect(&transaction, &PackageKit::Transaction::speedChanged, this, [this, &transaction]() {
        emitSpeed(transaction.speed());
    });
    connect(&transaction, &PackageKit::Transaction::percentageChanged, this, [this, &transaction]() {
        setPercent(transaction.percentage());
    });
}

void DolphinPackageInstaller::slotInstallationFailed(PackageKit::Transaction::Error error, const QString &details)
{
    setErrorString(xi18nc("@info:shell %1 is package name, %2 is error message, %3 is error e.g. 'ErrorNoNetwork'",
                          "Installing <application>%1</application> failed: %2 (%3)<nl/>Please try installing <application>%1</application> manually instead.",
                          m_packageName,
                          details,
                          QMetaEnum::fromType<PackageKit::Transaction::Error>().valueToKey(error)));
    setError(error);
    emitResult();
}
#endif