src/eric7/WebBrowser/QtHelp/HelpDocsInstaller.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 9153
506e35e424d5
child 9221
bf71ee032bb4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/WebBrowser/QtHelp/HelpDocsInstaller.py	Thu Jul 07 11:23:56 2022 +0200
@@ -0,0 +1,251 @@
+# -*- 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(docsPath.glob("*.qch")) == 0
+            ):
+                docsPath = (
+                    docsPath.parents[2] / "Docs" /
+                    "Qt-{0}.{1}".format(*qVersionTuple())
+                )
+        else:
+            # unsupported Qt version
+            return False
+        
+        files = 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 = 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