eric7/WebBrowser/QtHelp/HelpDocsInstaller.py

branch
eric7
changeset 8312
800c432b34c8
parent 8218
7c09585bd960
child 8314
e3642a6a1e71
diff -r 4e8b98454baa -r 800c432b34c8 eric7/WebBrowser/QtHelp/HelpDocsInstaller.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/WebBrowser/QtHelp/HelpDocsInstaller.py	Sat May 15 18:45:04 2021 +0200
@@ -0,0 +1,255 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a thread class populating and updating the QtHelp
+documentation database.
+"""
+
+import os
+
+from PyQt5.QtCore import (
+    pyqtSignal, QThread, Qt, QMutex, QDateTime, QDir, QLibraryInfo, QFileInfo
+)
+from PyQt5.QtHelp import QHelpEngineCore
+
+from eric6config 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 (string)
+        """
+        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", "qtconcurrent", "qtcore", "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", "qtqmltest", "qtquick", "qtquickcontrols",
+            "qtquickcontrols1", "qtquickdialogs", "qtquickextras",
+            "qtquicklayouts", "qtremoteobjects", "qtscript", "qtscripttools",
+            "qtscxml", "qtsensors", "qtserialbus", "qtserialport", "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.__installEric6Doc(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 (string)
+        @param version Qt version of the help documens (integer)
+        @param engine reference to the help engine (QHelpEngineCore)
+        @return flag indicating success (boolean)
+        """
+        versionKey = "qt_version_{0}@@{1}".format(version, name)
+        info = engine.customValue(versionKey, "")
+        lst = info.split('|')
+        
+        dt = QDateTime()
+        if len(lst) and lst[0]:
+            dt = QDateTime.fromString(lst[0], Qt.DateFormat.ISODate)
+        
+        qchFile = ""
+        if len(lst) == 2:
+            qchFile = lst[1]
+        
+        if version == 4:
+            docsPath = QDir(
+                QLibraryInfo.location(
+                    QLibraryInfo.LibraryLocation.DocumentationPath) +
+                QDir.separator() + "qch")
+        elif version == 5:
+            docsPath = QLibraryInfo.location(
+                QLibraryInfo.LibraryLocation.DocumentationPath)
+            if (
+                not os.path.isdir(docsPath) or
+                len(QDir(docsPath).entryList(["*.qch"])) == 0
+            ):
+                docsPathList = QDir.fromNativeSeparators(docsPath).split("/")
+                docsPath = os.sep.join(
+                    docsPathList[:-3] +
+                    ["Docs", "Qt-{0}.{1}".format(*qVersionTuple())])
+            docsPath = QDir(docsPath)
+        else:
+            # unsupported Qt version
+            return False
+        
+        files = docsPath.entryList(["*.qch"])
+        if not files:
+            engine.setCustomValue(
+                versionKey,
+                QDateTime().toString(Qt.DateFormat.ISODate) + '|')
+            return False
+        
+        for f in files:
+            if f.startswith(name + "."):
+                fi = QFileInfo(docsPath.absolutePath() + QDir.separator() + f)
+                namespace = QHelpEngineCore.namespaceName(
+                    fi.absoluteFilePath())
+                if not namespace:
+                    continue
+                
+                if (
+                    dt.isValid() and
+                    namespace in engine.registeredDocumentations() and
+                    (fi.lastModified().toString(Qt.DateFormat.ISODate) ==
+                     dt.toString(Qt.DateFormat.ISODate)) and
+                    qchFile == fi.absoluteFilePath()
+                ):
+                    return False
+                
+                if namespace in engine.registeredDocumentations():
+                    engine.unregisterDocumentation(namespace)
+                
+                if not engine.registerDocumentation(fi.absoluteFilePath()):
+                    self.errorMessage.emit(
+                        self.tr(
+                            """<p>The file <b>{0}</b> could not be"""
+                            """ registered. <br/>Reason: {1}</p>""")
+                        .format(fi.absoluteFilePath, engine.error())
+                    )
+                    return False
+                
+                engine.setCustomValue(
+                    versionKey,
+                    fi.lastModified().toString(Qt.DateFormat.ISODate) + '|' +
+                    fi.absoluteFilePath())
+                return True
+        
+        return False
+    
+    def __installEric6Doc(self, engine):
+        """
+        Private method to install/update the eric help documentation.
+        
+        @param engine reference to the help engine (QHelpEngineCore)
+        @return flag indicating success (boolean)
+        """
+        versionKey = "eric6_ide"
+        info = engine.customValue(versionKey, "")
+        lst = info.split('|')
+        
+        dt = QDateTime()
+        if len(lst) and lst[0]:
+            dt = QDateTime.fromString(lst[0], Qt.DateFormat.ISODate)
+        
+        qchFile = ""
+        if len(lst) == 2:
+            qchFile = lst[1]
+        
+        docsPath = QDir(getConfig("ericDocDir") + QDir.separator() + "Help")
+        
+        files = docsPath.entryList(["*.qch"])
+        if not files:
+            engine.setCustomValue(
+                versionKey, QDateTime().toString(Qt.DateFormat.ISODate) + '|')
+            return False
+        
+        for f in files:
+            if f == "source.qch":
+                fi = QFileInfo(docsPath.absolutePath() + QDir.separator() + f)
+                namespace = QHelpEngineCore.namespaceName(
+                    fi.absoluteFilePath())
+                if not namespace:
+                    continue
+                
+                if (
+                    dt.isValid() and
+                    namespace in engine.registeredDocumentations() and
+                    (fi.lastModified().toString(Qt.DateFormat.ISODate) ==
+                     dt.toString(Qt.DateFormat.ISODate)) and
+                    qchFile == fi.absoluteFilePath()
+                ):
+                    return False
+                
+                if namespace in engine.registeredDocumentations():
+                    engine.unregisterDocumentation(namespace)
+                
+                if not engine.registerDocumentation(fi.absoluteFilePath()):
+                    self.errorMessage.emit(
+                        self.tr(
+                            """<p>The file <b>{0}</b> could not be"""
+                            """ registered. <br/>Reason: {1}</p>""")
+                        .format(fi.absoluteFilePath, engine.error())
+                    )
+                    return False
+                
+                engine.setCustomValue(
+                    versionKey,
+                    fi.lastModified().toString(Qt.DateFormat.ISODate) + '|' +
+                    fi.absoluteFilePath())
+                return True
+        
+        return False

eric ide

mercurial