1/*
2 SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "kurlhandler_p.h"
8
9#include <kguiaddons_debug.h>
10
11#include <QCoreApplication>
12#include <QDebug>
13#include <QDesktopServices>
14#include <QLocale>
15#include <QProcess>
16#include <QStandardPaths>
17#include <QUrl>
18
19static const char s_khelpcenter_exec[] = "khelpcenter";
20
21static bool openWithKHelpCenter(const QUrl &url)
22{
23 const QString helpcenter = QStandardPaths::findExecutable(executableName: QString::fromLatin1(ba: s_khelpcenter_exec));
24 if (!helpcenter.isEmpty()) {
25 QUrl u(url);
26 if (u.path() == QLatin1Char('/')) {
27 const QString appName = QCoreApplication::applicationName();
28 u.setPath(path: appName);
29 }
30
31 QProcess::startDetached(program: helpcenter, arguments: QStringList(u.toString()));
32 return true;
33 }
34
35 return false;
36}
37
38KUrlHandler::KUrlHandler(QObject *parent)
39 : QObject(parent)
40{
41}
42
43void KUrlHandler::openHelp(const QUrl &url) const
44{
45 if (openWithKHelpCenter(url)) {
46 return;
47 }
48
49 const QUrl docUrl = concatDocsUrl(url);
50 if (docUrl.isValid()) {
51 QDesktopServices::openUrl(url: docUrl);
52 } else {
53 qCWarning(KGUIADDONS_LOG) << "Could not find a suitable handler for" << url.toString();
54 }
55}
56
57QUrl KUrlHandler::concatDocsUrl(const QUrl &url) const
58{
59 if (QCoreApplication::organizationDomain() != QLatin1String("kde.org")) {
60 return {};
61 }
62
63 // KHelpCenter is not available and it's a KDE application, open the docs at docs.kde.org
64 // with the default web browser on the system
65
66 QString path = url.path();
67 const QString fragment = url.fragment();
68 const QString common = QLatin1String("https://docs.kde.org/index.php?branch=stable5&language=") + QLocale().name();
69
70 const QString appName = QCoreApplication::applicationName();
71
72 // Special case for KCModules
73 if (appName == QLatin1String("systemsettings") && path.startsWith(s: QLatin1String("/kcontrol"))) {
74 // E.g. change "/kcontrol/fonts/index.html" to "&application=kcontrol/fonts&path=index.html"
75 // docs.kde.org will resolve the url and add the proper package name, e.g. plasma-workspace:
76 // https://docs.kde.org/stable5/en/plasma-workspace/kcontrol/fonts/index.html
77 QString kcmAppName(path);
78 kcmAppName.remove(i: 0, len: 1); // Remove leading "/"
79 const int idx = kcmAppName.indexOf(s: QLatin1String("/index.html"));
80 if (idx > 0) {
81 kcmAppName.truncate(pos: idx);
82 }
83
84 // Some KCModules have a valid fragment, e.g. kcontrol/powerdevil/index.html#advanced-settings
85 const QString tail = QLatin1String("index.html") + (!fragment.isEmpty() ? QLatin1Char('#') + fragment : QString{});
86
87 return QUrl(common + QLatin1String("&application=") + kcmAppName + QLatin1String("&path=") + tail);
88 }
89
90 // E.g. "help:/" and appName is "okular", e.g. opening Help -> Okular HandBook
91 if (path == QLatin1Char('/')) {
92 return QUrl(common + QLatin1String("&application=") + appName + QLatin1String("&path=") + QLatin1String("index.html"));
93 }
94
95 // E.g. "help:/okular/configure.html", don't repeat "appName"; e.g. clicking Help button in
96 // the "Settings -> Configure Okular" dialog
97 const QString redundant = QLatin1Char('/') + appName + QLatin1Char('/');
98 if (path.startsWith(s: redundant)) {
99 path.remove(i: 0, len: redundant.size());
100
101 if (!fragment.isEmpty()) {
102 // E.g. "help:/kinfocenter/index.html#kcm_memory", it's actually "kinfocenter/kcm_memory.html"
103 if (path == QLatin1String("index.html")) {
104 qCWarning(KGUIADDONS_LOG) << "X-DocPath entry in a .desktop file in" << appName << "is:" << appName + QLatin1String("/index.html#") + fragment
105 << ", however it should be:" << appName + QLatin1Char('/') + fragment + QLatin1String(".html");
106
107 path = fragment + QLatin1String(".html");
108 } else {
109 // E.g. "help:/okular/signatures.html#adding_digital_signatures"
110 path += QLatin1Char('#') + fragment;
111 }
112 }
113
114 return QUrl(common + QLatin1String("&application=") + appName + QLatin1String("&path=") + path);
115 }
116
117 return {};
118}
119
120Q_GLOBAL_STATIC(KUrlHandler, s_handler)
121
122static void initializeGlobalSettings()
123{
124 QDesktopServices::setUrlHandler(QStringLiteral("help"), receiver: s_handler, method: "openHelp");
125}
126
127Q_COREAPP_STARTUP_FUNCTION(initializeGlobalSettings)
128
129#include "moc_kurlhandler_p.cpp"
130

source code of kguiaddons/src/util/kurlhandler_p.cpp