File: systemsettingsrunner.cpp

package info (click to toggle)
systemsettings 4%3A6.5.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,968 kB
  • sloc: cpp: 2,848; xml: 174; python: 47; makefile: 3; sh: 3
file content (158 lines) | stat: -rw-r--r-- 6,828 bytes parent folder | download | duplicates (2)
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
    SPDX-FileCopyrightText: 2006 Aaron Seigo <aseigo@kde.org>
    SPDX-FileCopyrightText: 2014 Vishesh Handa <vhanda@kde.org>
    SPDX-FileCopyrightText: 2016-2020 Harald Sitter <sitter@kde.org>
    SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
    SPDX-FileCopyrightText: 2022 Natalie Clarius <natalie_clarius@yahoo.de>

    SPDX-License-Identifier: LGPL-2.0-only
*/

#include "systemsettingsrunner.h"

#include <algorithm>

#include <QMimeData>
#include <QUrl>
#include <QUrlQuery>

#include <KIO/CommandLauncherJob>
#include <KLocalizedString>
#include <KNotificationJobUiDelegate>
#include <KSycoca>
#include <PlasmaActivities/ResourceInstance>

#include "../app/kcmmetadatahelpers.h"

K_PLUGIN_CLASS_WITH_JSON(SystemsettingsRunner, "systemsettingsrunner.json")

SystemsettingsRunner::SystemsettingsRunner(QObject *parent, const KPluginMetaData &metaData)
    : KRunner::AbstractRunner(parent, metaData)
{
    addSyntax(QStringLiteral(":q:"), i18n("Finds system settings modules whose names or descriptions match :q:"));
    connect(this, &SystemsettingsRunner::prepare, this, [this]() {
        m_modules = findKCMsMetaData(MetaDataSource::All);
    });
    connect(this, &SystemsettingsRunner::teardown, this, [this]() {
        m_modules.clear();
    });
}

void SystemsettingsRunner::match(KRunner::RunnerContext &context)
{
    QList<KRunner::QueryMatch> matches;
    const QString query = context.query();
    const QStringList queryWords{query.split(QLatin1Char(' '))};
    for (const KPluginMetaData &data : std::as_const(m_modules)) {
        qreal relevance = -1;
        const auto checkMatchAndRelevance = [&query, &relevance, &queryWords](const QString &value, qreal relevanceValue) {
            if (value.startsWith(query, Qt::CaseInsensitive)) {
                relevance = relevanceValue + 0.1;
                return true;
            }
            for (const QString &queryWord : queryWords) {
                if (!value.contains(queryWord, Qt::CaseInsensitive)) {
                    return false;
                }
            }
            relevance = relevanceValue;
            return true;
        };

        const QString name = data.name();
        const QString description = data.description();
        const QStringList keywords = data.value(QStringLiteral("X-KDE-Keywords")).split(QLatin1Char(','));
        // check for matches and set relevance
        if (query.length() < 3) {
            if (name.startsWith(query, Qt::CaseInsensitive)) {
                relevance = 0.9;
            } else {
                continue;
            }
        } else if (name.compare(query, Qt::CaseInsensitive) == 0) {
            relevance = 1;
        } else if (checkMatchAndRelevance(name, 0.8)) { // name starts with query or contains all query words
        } else if (checkMatchAndRelevance(description, 0.5)) { // description starts with query or contains all query words
        } else if (std::any_of(keywords.begin(), keywords.end(), [&query](const QString &keyword) {
                       return keyword.startsWith(query, Qt::CaseInsensitive);
                   })) {
            if (keywords.contains(query, Qt::CaseInsensitive)) { // any of the keywords matches query
                relevance = 0.5;
            } else { // any of the keywords starts with query
                relevance = 0.2;
            }
        } else { // none of the properties matches
            continue; // skip this KCM
        }

        KRunner::QueryMatch::CategoryRelevance categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Low;
        if (name.compare(query, Qt::CaseInsensitive) == 0) { // name matches exactly
            categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Highest;
        } else if (name.startsWith(query, Qt::CaseInsensitive)) {
            categoryRelevance = KRunner::QueryMatch::CategoryRelevance::High;
        } else if (description.startsWith(query, Qt::CaseInsensitive)) {
            categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Moderate;
        } else if (keywords.contains(query, Qt::CaseInsensitive)) { // any of the keywords matches exactly
            categoryRelevance = KRunner::QueryMatch::CategoryRelevance::Moderate;
        }

        KRunner::QueryMatch match(this);
        match.setText(name);
        match.setUrls({QUrl(QLatin1String("applications://") + data.pluginId())});
        match.setSubtext(description);
        match.setIconName(data.iconName()); // If it is not set, KRunner will fall back to the runner's icon
        match.setId(data.pluginId()); // KRunner needs the id to adjust the relevance for often launched KCMs
        match.setData(QVariant::fromValue(data));
        match.setRelevance(relevance);
        match.setCategoryRelevance(categoryRelevance);

        if (isKinfoCenterKcm(data)) {
            match.setMatchCategory(i18nd("systemsettings", "System Information"));
        } else {
            match.setMatchCategory(i18nd("systemsettings", "System Settings"));
        }

        matches << match;
    }
    context.addMatches(matches);
}

void SystemsettingsRunner::run(const KRunner::RunnerContext & /*context*/, const KRunner::QueryMatch &match)
{
    const auto data = match.data().value<KPluginMetaData>();

    KIO::CommandLauncherJob *job = nullptr;
    if (isKinfoCenterKcm(data)) {
        job = new KIO::CommandLauncherJob(QStringLiteral("kinfocenter"), {data.pluginId()});
        job->setDesktopName(QStringLiteral("org.kde.kinfocenter"));
    } else if (!data.value(QStringLiteral("X-KDE-System-Settings-Parent-Category")).isEmpty()) {
        job = new KIO::CommandLauncherJob(QStringLiteral("systemsettings"), {data.pluginId()});
        job->setDesktopName(QStringLiteral("systemsettings"));
    } else {
        // Systemsettings only uses predefined namespaces that kcmshell5/6 also knows about
        job = new KIO::CommandLauncherJob(QStringLiteral("kcmshell6"), {data.pluginId()});
    }
    auto delegate = new KNotificationJobUiDelegate;
    delegate->setAutoErrorHandlingEnabled(true);
    job->setUiDelegate(delegate);
    job->start();

    KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("systemsettings:") + data.pluginId()), QStringLiteral("org.kde.krunner"));
}

QMimeData *SystemsettingsRunner::mimeDataForMatch(const KRunner::QueryMatch &match)
{
    const auto value = match.data().value<KPluginMetaData>();
    if (value.isValid()) {
        if (KService::Ptr ptr = KService::serviceByStorageId(value.pluginId() + QLatin1String(".desktop"))) {
            auto data = new QMimeData();
            data->setUrls(QList<QUrl>{QUrl::fromLocalFile(ptr->entryPath())});
            return data;
        }
    }
    return nullptr;
}

#include "systemsettingsrunner.moc"

#include "moc_systemsettingsrunner.cpp"