File indexing completed on 2024-12-08 12:18:39

0001 /*
0002     SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "kurlhandler_p.h"
0008 
0009 #include <kguiaddons_debug.h>
0010 
0011 #include <QCoreApplication>
0012 #include <QDebug>
0013 #include <QDesktopServices>
0014 #include <QLocale>
0015 #include <QProcess>
0016 #include <QStandardPaths>
0017 #include <QUrl>
0018 
0019 static const char s_khelpcenter_exec[] = "khelpcenter";
0020 
0021 static bool openWithKHelpCenter(const QUrl &url)
0022 {
0023     const QString helpcenter = QStandardPaths::findExecutable(QString::fromLatin1(s_khelpcenter_exec));
0024     if (!helpcenter.isEmpty()) {
0025         QUrl u(url);
0026         if (u.path() == QLatin1Char('/')) {
0027             const QString appName = QCoreApplication::applicationName();
0028             u.setPath(appName);
0029         }
0030 
0031         QProcess::startDetached(helpcenter, QStringList(u.toString()));
0032         return true;
0033     }
0034 
0035     return false;
0036 }
0037 
0038 KUrlHandler::KUrlHandler(QObject *parent)
0039     : QObject(parent)
0040 {
0041 }
0042 
0043 void KUrlHandler::openHelp(const QUrl &url) const
0044 {
0045     if (openWithKHelpCenter(url)) {
0046         return;
0047     }
0048 
0049     const QUrl docUrl = concatDocsUrl(url);
0050     if (docUrl.isValid()) {
0051         QDesktopServices::openUrl(docUrl);
0052     } else {
0053         qCWarning(KGUIADDONS_LOG) << "Could not find a suitable handler for" << url.toString();
0054     }
0055 }
0056 
0057 QUrl KUrlHandler::concatDocsUrl(const QUrl &url) const
0058 {
0059     if (QCoreApplication::organizationDomain() != QLatin1String("kde.org")) {
0060         return {};
0061     }
0062 
0063     // KHelpCenter is not available and it's a KDE application, open the docs at docs.kde.org
0064     // with the default web browser on the system
0065 
0066     QString path = url.path();
0067     const QString fragment = url.fragment();
0068     const QString common = QLatin1String("https://docs.kde.org/index.php?branch=stable5&language=") + QLocale().name();
0069 
0070     const QString appName = QCoreApplication::applicationName();
0071 
0072     // Special case for KCModules
0073     if (appName == QLatin1String("systemsettings") && path.startsWith(QLatin1String("/kcontrol"))) {
0074         // E.g. change "/kcontrol/fonts/index.html" to "&application=kcontrol/fonts&path=index.html"
0075         // docs.kde.org will resolve the url and add the proper package name, e.g. plasma-workspace:
0076         // https://docs.kde.org/stable5/en/plasma-workspace/kcontrol/fonts/index.html
0077         QString kcmAppName(path);
0078         kcmAppName.remove(0, 1); // Remove leading "/"
0079         const int idx = kcmAppName.indexOf(QLatin1String("/index.html"));
0080         if (idx > 0) {
0081             kcmAppName.truncate(idx);
0082         }
0083 
0084         // Some KCModules have a valid fragment, e.g. kcontrol/powerdevil/index.html#advanced-settings
0085         const QString tail = QLatin1String("index.html") + (!fragment.isEmpty() ? QLatin1Char('#') + fragment : QString{});
0086 
0087         return QUrl(common + QLatin1String("&application=") + kcmAppName + QLatin1String("&path=") + tail);
0088     }
0089 
0090     // E.g. "help:/" and appName is "okular", e.g. opening Help -> Okular HandBook
0091     if (path == QLatin1Char('/')) {
0092         return QUrl(common + QLatin1String("&application=") + appName + QLatin1String("&path=") + QLatin1String("index.html"));
0093     }
0094 
0095     // E.g. "help:/okular/configure.html", don't repeat "appName"; e.g. clicking Help button in
0096     // the "Settings -> Configure Okular" dialog
0097     const QString redundant = QLatin1Char('/') + appName + QLatin1Char('/');
0098     if (path.startsWith(redundant)) {
0099         path.remove(0, redundant.size());
0100 
0101         if (!fragment.isEmpty()) {
0102             // E.g. "help:/kinfocenter/index.html#kcm_memory", it's actually "kinfocenter/kcm_memory.html"
0103             if (path == QLatin1String("index.html")) {
0104                 qCWarning(KGUIADDONS_LOG) << "X-DocPath entry in a .desktop file in" << appName << "is:" << appName + QLatin1String("/index.html#") + fragment
0105                                           << ", however it should be:" << appName + QLatin1Char('/') + fragment + QLatin1String(".html");
0106 
0107                 path = fragment + QLatin1String(".html");
0108             } else {
0109                 // E.g. "help:/okular/signatures.html#adding_digital_signatures"
0110                 path += QLatin1Char('#') + fragment;
0111             }
0112         }
0113 
0114         return QUrl(common + QLatin1String("&application=") + appName + QLatin1String("&path=") + path);
0115     }
0116 
0117     return {};
0118 }
0119 
0120 Q_GLOBAL_STATIC(KUrlHandler, s_handler)
0121 
0122 static void initializeGlobalSettings()
0123 {
0124     QDesktopServices::setUrlHandler(QStringLiteral("help"), s_handler, "openHelp");
0125 }
0126 
0127 Q_COREAPP_STARTUP_FUNCTION(initializeGlobalSettings)
0128 
0129 #include "moc_kurlhandler_p.cpp"