File indexing completed on 2024-05-05 04:40:51

0001 /*
0002     SPDX-FileCopyrightText: 2009 Aleix Pol <aleixpol@kde.org>
0003     SPDX-FileCopyrightText: 2009 David Nolden <david.nolden.kdevelop@art-master.de>
0004     SPDX-FileCopyrightText: 2010 Benjamin Port <port.benjamin@gmail.com>
0005     SPDX-FileCopyrightText: 2016 Andreas Cord-Landwehr <cordlandwehr@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "qthelpqtdoc.h"
0011 #include "debug.h"
0012 
0013 #include <QDir>
0014 #include <QIcon>
0015 #include <QStandardPaths>
0016 
0017 #include <KLocalizedString>
0018 #include <QProcess>
0019 
0020 #include <algorithm>
0021 
0022 namespace {
0023 
0024 QString qmakeCandidate()
0025 {
0026     // return the first qmake executable we can find
0027     const QStringList candidates {
0028         QStringLiteral("qmake"),
0029         QStringLiteral("qmake-qt4"),
0030         QStringLiteral("qmake-qt5")
0031     };
0032     auto it = std::find_if(candidates.constBegin(), candidates.constEnd(), [](const QString& candidate) {
0033         return !QStandardPaths::findExecutable(candidate).isEmpty();
0034     });
0035     return it != candidates.constEnd() ? *it : QString();
0036 }
0037 
0038 }
0039 
0040 QtHelpQtDoc::QtHelpQtDoc(QObject *parent, const QVariantList &args)
0041     : QtHelpProviderAbstract(parent, QStringLiteral("qthelpcollection.qhc"), args)
0042     , m_path(QString())
0043 {
0044     Q_UNUSED(args);
0045     registerDocumentations();
0046 }
0047 
0048 QtHelpQtDoc::~QtHelpQtDoc() = default;
0049 
0050 void QtHelpQtDoc::registerDocumentations()
0051 {
0052     Q_ASSERT(!m_isInitialized);
0053     const QString qmake = qmakeCandidate();
0054     if (!qmake.isEmpty()) {
0055         auto* p = new QProcess(this);
0056         p->setProcessChannelMode(QProcess::MergedChannels);
0057         p->setProgram(qmake);
0058         p->setArguments({QLatin1String("-query"), QLatin1String("QT_INSTALL_DOCS")});
0059         connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this, p](int code) {
0060             if (code == QProcess::NormalExit) {
0061                 m_path = QDir::fromNativeSeparators(QString::fromLatin1(p->readAllStandardOutput().trimmed()));
0062                 qCDebug(QTHELP) << "Detected doc path:" << m_path;
0063             } else {
0064                 qCCritical(QTHELP) << "qmake query returned error:" << QString::fromLatin1(p->readAllStandardError());
0065                 qCDebug(QTHELP) << "last standard output was:" << QString::fromLatin1(p->readAllStandardOutput());
0066             }
0067 
0068             p->deleteLater();
0069             m_isInitialized = true;
0070         });
0071         p->start();
0072     } else {
0073         m_isInitialized = true;
0074     }
0075 }
0076 
0077 void QtHelpQtDoc::loadDocumentation()
0078 {
0079     if(m_path.isEmpty()) {
0080         return;
0081     }
0082 
0083     const QStringList files = qchFiles();
0084     if(files.isEmpty()) {
0085         qCWarning(QTHELP) << "could not find QCH file in directory" << m_path;
0086         return;
0087     }
0088 
0089     for (const QString& fileName : files) {
0090         QString fileNamespace = QHelpEngineCore::namespaceName(fileName);
0091         if (!fileNamespace.isEmpty() && !m_engine.registeredDocumentations().contains(fileNamespace)) {
0092             qCDebug(QTHELP) << "loading doc" << fileName << fileNamespace;
0093             if(!m_engine.registerDocumentation(fileName))
0094                 qCCritical(QTHELP) << "error >> " << fileName << m_engine.error();
0095         }
0096     }
0097 }
0098 
0099 void QtHelpQtDoc::unloadDocumentation()
0100 {
0101     const auto fileNames = qchFiles();
0102     for (const QString& fileName : fileNames) {
0103         QString fileNamespace = QHelpEngineCore::namespaceName(fileName);
0104         if(!fileName.isEmpty() && m_engine.registeredDocumentations().contains(fileNamespace)) {
0105             m_engine.unregisterDocumentation(fileName);
0106         }
0107     }
0108 }
0109 
0110 QStringList QtHelpQtDoc::qchFiles() const
0111 {
0112     QStringList files;
0113 
0114     const QVector<QString> paths{ // test directories
0115         m_path,
0116         m_path + QLatin1String("/qch/"),
0117     };
0118 
0119     for (const auto& path : paths) {
0120         QDir d(path);
0121         if(path.isEmpty() || !d.exists()) {
0122             continue;
0123         }
0124         const auto fileInfos = d.entryInfoList(QDir::Files);
0125         for (const auto& file : fileInfos) {
0126             files << file.absoluteFilePath();
0127         }
0128     }
0129     if (files.isEmpty()) {
0130         qCDebug(QTHELP) << "no QCH file found at all";
0131     }
0132     return files;
0133 }
0134 
0135 QIcon QtHelpQtDoc::icon() const
0136 {
0137     return QIcon::fromTheme(QStringLiteral("qtlogo"));
0138 }
0139 
0140 QString QtHelpQtDoc::name() const
0141 {
0142     return i18n("QtHelp");
0143 }
0144 
0145 #include "moc_qthelpqtdoc.cpp"