src/eric7/WebBrowser/QtHelp/HelpDocsInstaller.py

Mon, 15 Aug 2022 14:08:34 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 15 Aug 2022 14:08:34 +0200
branch
eric7
changeset 9286
f6f950e4c8f0
parent 9221
bf71ee032bb4
child 9413
80c06d472826
permissions
-rw-r--r--

Fixed a few issues related to the use of pathlib.Path().glob().

# -*- coding: utf-8 -*-

# Copyright (c) 2009 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a thread class populating and updating the QtHelp
documentation database.
"""

import datetime
import pathlib

from PyQt6.QtCore import pyqtSignal, QThread, QMutex, QLibraryInfo
from PyQt6.QtHelp import QHelpEngineCore

from eric7config import getConfig

from Globals import qVersionTuple


class HelpDocsInstaller(QThread):
    """
    Class implementing the worker thread populating and updating the QtHelp
    documentation database.

    @signal errorMessage(str) emitted, if an error occurred during
        the installation of the documentation
    @signal docsInstalled(bool) emitted after the installation has finished
    """

    errorMessage = pyqtSignal(str)
    docsInstalled = pyqtSignal(bool)

    def __init__(self, collection):
        """
        Constructor

        @param collection full pathname of the collection file
        @type str
        """
        super().__init__()

        self.__abort = False
        self.__collection = collection
        self.__mutex = QMutex()

    def stop(self):
        """
        Public slot to stop the installation procedure.
        """
        if not self.isRunning():
            return

        self.__mutex.lock()
        self.__abort = True
        self.__mutex.unlock()
        self.wait()

    def installDocs(self):
        """
        Public method to start the installation procedure.
        """
        self.start(QThread.Priority.LowPriority)

    def run(self):
        """
        Public method executed by the thread.
        """
        engine = QHelpEngineCore(self.__collection)
        changes = False

        qt5Docs = [
            "activeqt",
            "qdoc",
            "qmake",
            "qt3d",
            "qt3drenderer",
            "qtandroidextras",
            "qtassistant",
            "qtbluetooth",
            "qtcanvas3d",
            "qtcharts",
            "qtcmake",
            "qtconcurrent",
            "qtcore",
            "qtdatavis3d",
            "qtdatavisualization",
            "qtdbus",
            "qtdesigner",
            "qtdistancefieldgenerator",
            "qtdoc",
            "qtenginio",
            "qtenginiooverview",
            "qtenginoqml",
            "qtgamepad",
            "qtgraphicaleffects",
            "qtgui",
            "qthelp",
            "qtimageformats",
            "qtlabscalendar",
            "qtlabsplatform",
            "qtlabscontrols",
            "qtlinguist",
            "qtlocation",
            "qtlottieanimation",
            "qtmaxextras",
            "qtmultimedia",
            "qtmultimediawidgets",
            "qtnetwork",
            "qtnetworkauth",
            "qtnfc",
            "qtopengl",
            "qtplatformheaders",
            "qtpositioning",
            "qtprintsupport",
            "qtpurchasing",
            "qtqml",
            "qtqmlmodels",
            "qtqmltest",
            "qtquick",
            "qtquick3d",
            "qtquickcontrols",
            "qtquickcontrols1",
            "qtquickdialogs",
            "qtquickextras",
            "qtquicklayouts",
            "qtquicktimeline",
            "qtremoteobjects",
            "qtscript",
            "qtscripttools",
            "qtscxml",
            "qtsensors",
            "qtserialbus",
            "qtserialport",
            "qtshadertools",
            "qtspeech",
            "qtsql",
            "qtsvg",
            "qttest",
            "qttestlib",
            "qtuitools",
            "qtvirtualkeyboard",
            "qtwaylandcompositor",
            "qtwebchannel",
            "qtwebengine",
            "qtwebenginewidgets",
            "qtwebkit",
            "qtwebkitexamples",
            "qtwebsockets",
            "qtwebview",
            "qtwidgets",
            "qtwinextras",
            "qtx11extras",
            "qtxml",
            "qtxmlpatterns",
        ]
        for qtDocs, version in [(qt5Docs, 5)]:
            for doc in qtDocs:
                changes |= self.__installQtDoc(doc, version, engine)
                self.__mutex.lock()
                if self.__abort:
                    engine = None
                    self.__mutex.unlock()
                    return
                self.__mutex.unlock()

        changes |= self.__installEric7Doc(engine)
        engine = None
        del engine
        self.docsInstalled.emit(changes)

    def __installQtDoc(self, name, version, engine):
        """
        Private method to install/update a Qt help document.

        @param name name of the Qt help document
        @type str
        @param version Qt version of the help documents
        @type int
        @param engine reference to the help engine
        @type QHelpEngineCore
        @return flag indicating success
        @rtype bool
        """
        versionKey = "qt_version_{0}@@{1}".format(version, name)
        info = engine.customValue(versionKey, "")
        lst = info.split("|")

        dt = None
        if len(lst) and lst[0]:
            dt = datetime.datetime.fromisoformat(lst[0])

        qchFile = ""
        if len(lst) == 2:
            qchFile = lst[1]

        if version == 5:
            docsPath = pathlib.Path(
                QLibraryInfo.path(QLibraryInfo.LibraryPath.DocumentationPath)
            )
            if not docsPath.is_dir() or len(list(docsPath.glob("*.qch"))) == 0:
                docsPath = (
                    docsPath.parents[2] / "Docs" / "Qt-{0}.{1}".format(*qVersionTuple())
                )
        else:
            # unsupported Qt version
            return False

        files = list(docsPath.glob("*.qch"))
        if not files:
            engine.setCustomValue(versionKey, "|")
            return False

        for f in files:
            if f.stem == name:
                namespace = QHelpEngineCore.namespaceName(str(f.resolve()))
                if not namespace:
                    continue

                if (
                    dt is not None
                    and namespace in engine.registeredDocumentations()
                    and (datetime.datetime.fromtimestamp(f.stat().st_mtime) == dt)
                    and qchFile == str(f.resolve())
                ):
                    return False

                if namespace in engine.registeredDocumentations():
                    engine.unregisterDocumentation(namespace)

                if not engine.registerDocumentation(str(f.resolve())):
                    self.errorMessage.emit(
                        self.tr(
                            """<p>The file <b>{0}</b> could not be"""
                            """ registered. <br/>Reason: {1}</p>"""
                        ).format(f, engine.error())
                    )
                    return False

                engine.setCustomValue(
                    versionKey,
                    datetime.datetime.fromtimestamp(f.stat().st_mtime).isoformat()
                    + "|"
                    + str(f.resolve()),
                )
                return True

        return False

    def __installEric7Doc(self, engine):
        """
        Private method to install/update the eric help documentation.

        @param engine reference to the help engine
        @type QHelpEngineCore
        @return flag indicating success
        @rtype bool
        """
        versionKey = "eric7_ide"
        info = engine.customValue(versionKey, "")
        lst = info.split("|")

        dt = None
        if len(lst) and lst[0]:
            dt = datetime.datetime.fromisoformat(lst[0])

        qchFile = ""
        if len(lst) == 2:
            qchFile = lst[1]

        docsPath = pathlib.Path(getConfig("ericDocDir")) / "Help"

        files = list(docsPath.glob("*.qch"))
        if not files:
            engine.setCustomValue(versionKey, "|")
            return False

        for f in files:
            if f.name == "source.qch":
                namespace = QHelpEngineCore.namespaceName(str(f.resolve()))
                if not namespace:
                    continue

                if (
                    dt is not None
                    and namespace in engine.registeredDocumentations()
                    and (datetime.datetime.fromtimestamp(f.stat().st_mtime) == dt)
                    and qchFile == str(f.resolve())
                ):
                    return False

                if namespace in engine.registeredDocumentations():
                    engine.unregisterDocumentation(namespace)

                if not engine.registerDocumentation(str(f.resolve())):
                    self.errorMessage.emit(
                        self.tr(
                            """<p>The file <b>{0}</b> could not be"""
                            """ registered. <br/>Reason: {1}</p>"""
                        ).format(f, engine.error())
                    )
                    return False

                engine.setCustomValue(
                    versionKey,
                    datetime.datetime.fromtimestamp(f.stat().st_mtime).isoformat()
                    + "|"
                    + str(f.resolve()),
                )
                return True

        return False

eric ide

mercurial