FrameworkIntegration

kns/main.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2016 Aleix Pol Gonzalez <aleixpol@kde.org>
4 SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
5
6 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7*/
8
9#include <QCoreApplication>
10#include <QDebug>
11#include <QFile>
12#include <QFileInfo>
13#include <QStandardPaths>
14#include <QTimer>
15#include <QUrl>
16#include <QUrlQuery>
17
18#include <KLocalizedString>
19
20#include <KNotification>
21
22#include <KNSCore/EngineBase>
23#include <KNSCore/Question>
24#include <KNSCore/QuestionManager>
25#include <KNSCore/ResultsStream>
26#include <KNSCore/Transaction>
27
28#include "knshandlerversion.h"
29
30/**
31 * Unfortunately there are two knsrc files for the window decorations, but only one is used in the KCM.
32 * But both are used by third parties, consequently we can not remove one. To solve this we create a symlink
33 * which links the old cache file to the new cache file, which is exposed on the GUI.
34 * This way users can again remove window decorations that are installed as a dependency of a global theme.
35 * BUG: 414570
36 */
37void createSymlinkForWindowDecorations()
38{
40 // If we have created the symbolic link already we can exit the function here
41 if (info.isSymbolicLink()) {
42 return;
43 }
44 // Delete this file, it the KNS entries are not exposed in any GUI
45 if (info.exists()) {
46 QFile::remove(info.absoluteFilePath());
47 }
48 QFileInfo newFileInfo(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/knewstuff3/window-decorations.knsregistry"));
49 QFile file(newFileInfo.absoluteFilePath());
50 // Make sure that the file exists
51 if (!newFileInfo.exists()) {
52 file.open(QFile::WriteOnly);
53 file.close();
54 }
55 file.link(info.absoluteFilePath());
56}
57
58int main(int argc, char **argv)
59{
60 createSymlinkForWindowDecorations();
61 QCoreApplication app(argc, argv);
62 app.setApplicationName(QStringLiteral("kpackage-knshandler"));
63 app.setApplicationVersion(knshandlerversion);
64 app.setQuitLockEnabled(false);
65 Q_ASSERT(app.arguments().count() == 2);
66
67#ifdef TEST
69#endif
70
71 const QUrl url(app.arguments().last());
72 Q_ASSERT(url.isValid());
73 Q_ASSERT(url.scheme() == QLatin1String("kns"));
74
75 QString knsname;
76 const QStringList availableConfigFiles = KNSCore::EngineBase::availableConfigFiles();
77 auto knsNameIt = std::find_if(availableConfigFiles.begin(), availableConfigFiles.end(), [&url](const QString &availableFile) {
78 return availableFile.endsWith(QLatin1String("/") + url.host());
79 });
80
81 if (knsNameIt == availableConfigFiles.end()) {
82 qWarning() << "couldn't find knsrc file for" << url.host();
83 return 1;
84 } else {
85 knsname = *knsNameIt;
86 }
87
88 const auto pathParts = url.path().split(QLatin1Char('/'), Qt::SkipEmptyParts);
89 if (pathParts.size() != 2) {
90 qWarning() << "wrong format in the url path" << url << pathParts;
91 return 1;
92 }
93 const auto providerid = pathParts.at(0);
94 const auto entryid = pathParts.at(1);
95 int linkid = 1;
96 if (url.hasQuery()) {
97 QUrlQuery query(url);
98 if (query.hasQueryItem(QStringLiteral("linkid"))) {
99 bool ok;
100 linkid = query.queryItemValue(QStringLiteral("linkid")).toInt(&ok);
101 if (!ok) {
102 qWarning() << "linkid is not an integer" << url << pathParts;
103 return 1;
104 }
105 }
106 }
107
108 KNSCore::EngineBase engine;
109 int installedCount = 0;
110 QObject::connect(KNSCore::QuestionManager::instance(), &KNSCore::QuestionManager::askQuestion, &engine, [](KNSCore::Question *question) {
111 auto discardQuestion = [question]() {
112 question->setResponse(KNSCore::Question::InvalidResponse);
113 };
114 switch (question->questionType()) {
115 case KNSCore::Question::YesNoQuestion: {
116 auto f = KNotification::event(KNotification::StandardEvent::Notification, question->title(), question->question());
117
118 auto *yes = f->addAction(i18n("Yes"));
119 QObject::connect(yes, &KNotificationAction::activated, question, [question] {
120 question->setResponse(KNSCore::Question::YesResponse);
121 });
122
123 auto *no = f->addAction(i18n("No"));
124 QObject::connect(no, &KNotificationAction::activated, question, [question] {
125 question->setResponse(KNSCore::Question::NoResponse);
126 });
127
128 QObject::connect(f, &KNotification::closed, question, discardQuestion);
129 } break;
130 case KNSCore::Question::ContinueCancelQuestion: {
131 auto f = KNotification::event(KNotification::StandardEvent::Notification, question->title(), question->question());
132
133 auto *continueAction = f->addAction(i18n("Continue"));
134 QObject::connect(continueAction, &KNotificationAction::activated, question, [question]() {
135 question->setResponse(KNSCore::Question::ContinueResponse);
136 });
137
138 auto *cancelAction = f->addAction(i18n("Cancel"));
139 QObject::connect(cancelAction, &KNotificationAction::activated, question, [question]() {
140 question->setResponse(KNSCore::Question::CancelResponse);
141 });
142
143 QObject::connect(f, &KNotification::closed, question, discardQuestion);
144 } break;
145 case KNSCore::Question::InputTextQuestion:
146 case KNSCore::Question::SelectFromListQuestion:
147 case KNSCore::Question::PasswordQuestion:
148 discardQuestion();
149 break;
150 }
151 });
152
153 const auto onError = [](KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata) {
154 qWarning() << "kns error:" << errorCode << message << metadata;
156 };
157
158 bool entryWasFound = false;
159 const auto onEntriesLoded = [providerid, linkid, &installedCount, &engine, &entryWasFound, onError](const KNSCore::Entry::List list) {
160 Q_ASSERT(list.size() == 1);
161 entryWasFound = true;
162 const auto entry = list.first();
163 if (providerid != entry.providerId()) {
164 qWarning() << "Wrong provider" << providerid << "instead of" << entry.providerId();
166 } else if (entry.status() == KNSCore::Entry::Downloadable) {
167 qDebug() << "installing...";
168 installedCount++;
169 auto transaction = KNSCore::Transaction::install(&engine, entry, linkid);
171 QObject::connect(transaction, &KNSCore::Transaction::signalEntryEvent, [&installedCount](auto entry, auto event) {
173 if (entry.status() == KNSCore::Entry::Installed) {
174 installedCount--;
175 }
176 if (installedCount == 0) {
178 }
179 }
180 });
181 } else if (installedCount == 0) {
182 qDebug() << "already installed.";
184 }
185 };
186 QObject::connect(&engine, &KNSCore::EngineBase::signalProvidersLoaded, &engine, [&engine, &entryid, onEntriesLoded, &entryWasFound]() {
187 qWarning() << "providers are loaded";
188 KNSCore::Provider::SearchRequest request(KNSCore::Provider::Newest, KNSCore::Provider::ExactEntryId, entryid, QStringList{}, 0);
189 KNSCore::ResultsStream *results = engine.search(request);
190 QObject::connect(results, &KNSCore::ResultsStream::entriesFound, &engine, onEntriesLoded);
191 QObject::connect(results, &KNSCore::ResultsStream::finished, &engine, [&entryWasFound, &entryid]() {
192 if (!entryWasFound) {
193 qWarning() << "Entry with id" << entryid << "could not be found";
195 }
196 });
197 results->fetch();
198 });
199
200 QObject::connect(&engine, &KNSCore::EngineBase::signalErrorCode, &engine, onError);
201 if (!engine.init(knsname)) {
202 qWarning() << "couldn't initialize" << knsname;
203 return 1;
204 }
205 return app.exec();
206}
void signalErrorCode(KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata)
static QStringList availableConfigFiles()
void setResponse(const QString &response)
static Transaction * install(EngineBase *engine, const Entry &entry, int linkId=1)
void signalEntryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event)
void signalErrorCode(KNSCore::ErrorCode::ErrorCode errorCode, const QString &message, const QVariant &metadata)
static KNotification * event(const QString &eventId, const QString &text=QString(), const QPixmap &pixmap=QPixmap(), const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
QString i18n(const char *text, const TYPE &arg...)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
void exit(int returnCode)
bool remove()
const_reference at(qsizetype i) const const
iterator begin()
iterator end()
T & first()
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void setTestModeEnabled(bool testMode)
QString writableLocation(StandardLocation type)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
SkipEmptyParts
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.