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 | |
19 | static const char s_khelpcenter_exec[] = "khelpcenter" ; |
20 | |
21 | static 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 | |
38 | KUrlHandler::KUrlHandler(QObject *parent) |
39 | : QObject(parent) |
40 | { |
41 | } |
42 | |
43 | void 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 | |
57 | QUrl 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 | |
120 | Q_GLOBAL_STATIC(KUrlHandler, s_handler) |
121 | |
122 | static void initializeGlobalSettings() |
123 | { |
124 | QDesktopServices::setUrlHandler(QStringLiteral("help" ), receiver: s_handler, method: "openHelp" ); |
125 | } |
126 | |
127 | Q_COREAPP_STARTUP_FUNCTION(initializeGlobalSettings) |
128 | |
129 | #include "moc_kurlhandler_p.cpp" |
130 | |