Continued porting the web browser. QtWebEngine

Sat, 19 Mar 2016 16:05:11 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 19 Mar 2016 16:05:11 +0100
branch
QtWebEngine
changeset 4875
4ee26909ac0d
parent 4870
72901685681d
child 4880
561f2bd9cfb9

Continued porting the web browser.

- ported the QtHelp support

Documentation/Help/source.qch file | annotate | diff | comparison | revisions
Preferences/ConfigurationDialog.py file | annotate | diff | comparison | revisions
Preferences/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/Network/NetworkManager.py file | annotate | diff | comparison | revisions
WebBrowser/Network/QtHelpSchemeHandler.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/HelpDocsInstaller.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/HelpIndexWidget.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/HelpSearchWidget.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/HelpTocWidget.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/HelpTopicDialog.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/HelpTopicDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/QtHelpDocumentationDialog.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/QtHelpDocumentationDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/QtHelpFiltersDialog.py file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/QtHelpFiltersDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/QtHelp/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
eric6_browser.py file | annotate | diff | comparison | revisions
Binary file Documentation/Help/source.qch has changed
--- a/Preferences/ConfigurationDialog.py	Sat Mar 19 12:13:09 2016 +0100
+++ b/Preferences/ConfigurationDialog.py	Sat Mar 19 16:05:11 2016 +0100
@@ -434,11 +434,10 @@
                 [self.tr("Security"), "preferences-security.png",
                  "SecurityPage", None, None],
                 
-                # TODO: QtHelp
-##                "helpDocumentationPage":
-##                [self.tr("Help Documentation"),
-##                 "preferences-helpdocumentation.png",
-##                 "HelpDocumentationPage", None, None],
+                "helpDocumentationPage":
+                [self.tr("Help Documentation"),
+                 "preferences-helpdocumentation.png",
+                 "HelpDocumentationPage", None, None],
                 
                 "webBrowserAppearancePage":
                 [self.tr("Appearance"), "preferences-styles.png",
--- a/Preferences/__init__.py	Sat Mar 19 12:13:09 2016 +0100
+++ b/Preferences/__init__.py	Sat Mar 19 16:05:11 2016 +0100
@@ -2781,6 +2781,7 @@
         from Utilities.crypto import pwConvert
         return pwConvert(prefClass.settings.value(
             "WebBrowser/" + key, prefClass.helpDefaults[key]), encode=False)
+    # TODO: QtHelp
 ##    elif key == "HelpViewerType":
 ##        # special treatment to adjust for missing QtWebKit
 ##        value = int(prefClass.settings.value(
--- a/WebBrowser/Network/NetworkManager.py	Sat Mar 19 12:13:09 2016 +0100
+++ b/WebBrowser/Network/NetworkManager.py	Sat Mar 19 16:05:11 2016 +0100
@@ -39,10 +39,11 @@
     """
     changed = pyqtSignal()
     
-    def __init__(self, parent=None):
+    def __init__(self, engine, parent=None):
         """
         Constructor
         
+        @param engine reference to the help engine (QHelpEngine)
         @param parent reference to the parent object (QObject)
         """
         super(NetworkManager, self).__init__(parent)
@@ -79,6 +80,12 @@
         WebBrowserWindow.webProfile().installUrlSchemeHandler(
             QByteArray(b"eric"), self.__ericSchemeHandler)
         
+        if engine:
+            from .QtHelpSchemeHandler import QtHelpSchemeHandler
+            self.__qtHelpSchemeHandler = QtHelpSchemeHandler(engine)
+            WebBrowserWindow.webProfile().installUrlSchemeHandler(
+                QByteArray(b"qthelp"), self.__qtHelpSchemeHandler)
+        
         self.__interceptor = NetworkUrlInterceptor(self)
         WebBrowserWindow.webProfile().setRequestInterceptor(self.__interceptor)
         
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/Network/QtHelpSchemeHandler.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,283 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a scheme access handler for QtHelp.
+"""
+
+from __future__ import unicode_literals
+
+import mimetypes
+import os
+
+from PyQt5.QtCore import pyqtSignal, QByteArray, QIODevice, QBuffer
+from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler, \
+    QWebEngineUrlRequestJob
+
+##from .SchemeAccessHandler import SchemeAccessHandler
+##
+##from .NetworkReply import NetworkReply
+##
+QtDocPath = "qthelp://org.qt-project."
+
+ExtensionMap = {
+    ".bmp": "image/bmp",
+    ".css": "text/css",
+    ".gif": "image/gif",
+    ".html": "text/html",
+    ".htm": "text/html",
+    ".ico": "image/x-icon",
+    ".jpeg": "image/jpeg",
+    ".jpg": "image/jpeg",
+    ".js": "application/x-javascript",
+    ".mng": "video/x-mng",
+    ".pbm": "image/x-portable-bitmap",
+    ".pgm": "image/x-portable-graymap",
+    ".pdf": "application/pdf",
+    ".png": "image/png",
+    ".ppm": "image/x-portable-pixmap",
+    ".rss": "application/rss+xml",
+    ".svg": "image/svg+xml",
+    ".svgz": "image/svg+xml",
+    ".text": "text/plain",
+    ".tif": "image/tiff",
+    ".tiff": "image/tiff",
+    ".txt": "text/plain",
+    ".xbm": "image/x-xbitmap",
+    ".xml": "text/xml",
+    ".xpm": "image/x-xpm",
+    ".xsl": "text/xsl",
+    ".xhtml": "application/xhtml+xml",
+    ".wml": "text/vnd.wap.wml",
+    ".wmlc": "application/vnd.wap.wmlc",
+}
+
+
+class QtHelpSchemeHandler(QWebEngineUrlSchemeHandler):
+    """
+    Class implementing a scheme handler for the qthelp: scheme.
+    """
+    def __init__(self, engine, parent=None):
+        """
+        Constructor
+        
+        @param engine reference to the help engine
+        @type QHelpEngine
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(QtHelpSchemeHandler, self).__init__(parent)
+        
+        self.__engine = engine
+        
+        self.__replies = []
+    
+    def requestStarted(self, job):
+        """
+        Public method handling the URL request.
+        
+        @param job URL request job
+        @type QWebEngineUrlRequestJob
+        """
+        if job.requestUrl().scheme() == "qthelp":
+            reply = QtHelpSchemeReply(job, self.__engine)
+            reply.closed.connect(self.__replyClosed)
+            self.__replies.append(reply)
+            job.reply(reply.mimeType(), reply)
+        else:
+            job.fail(QWebEngineUrlRequestJob.UrlInvalid)
+    
+    def __replyClosed(self):
+        """
+        Private slot handling the closed signal of a reply.
+        """
+        object = self.sender()
+        if object and object in self.__replies:
+            self.__replies.remove(object)
+
+
+class QtHelpSchemeReply(QIODevice):
+    """
+    Class implementing a reply for a requested qthelp: page.
+    
+    @signal closed emitted to signal that the web engine has read
+        the data
+    """
+    closed = pyqtSignal()
+    
+    def __init__(self, job, engine, parent=None):
+        """
+        Constructor
+        
+        @param job reference to the URL request
+        @type QWebEngineUrlRequestJob
+        @param engine reference to the help engine
+        @type QHelpEngine
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(QtHelpSchemeReply, self).__init__(parent)
+        
+        url = job.requestUrl()
+        strUrl = url.toString()
+        
+        self.__buffer = QBuffer()
+        
+        # For some reason the url to load maybe wrong (passed from web engine)
+        # though the css file and the references inside should work that way.
+        # One possible problem might be that the css is loaded at the same
+        # level as the html, thus a path inside the css like
+        # (../images/foo.png) might cd out of the virtual folder
+        if not engine.findFile(url).isValid():
+            if strUrl.startswith(QtDocPath):
+                newUrl = job.requestUrl()
+                if not newUrl.path().startswith("/qdoc/"):
+                    newUrl.setPath("/qdoc" + newUrl.path())
+                    url = newUrl
+                    strUrl = url.toString()
+        
+        self.__mimeType = mimetypes.guess_type(strUrl)[0]
+        if self.__mimeType is None:
+            # do our own (limited) guessing
+            self.__mimeType = self.__mimeFromUrl(url)
+        
+        if engine.findFile(url).isValid():
+            data = engine.fileData(url)
+        else:
+            data = QByteArray(self.tr(
+                """<html>"""
+                """<head><title>Error 404...</title></head>"""
+                """<body><div align="center"><br><br>"""
+                """<h1>The page could not be found</h1><br>"""
+                """<h3>'{0}'</h3></div></body>"""
+                """</html>""").format(strUrl)
+                .encode("utf-8"))
+        
+        self.__buffer.setData(data)
+        self.__buffer.open(QIODevice.ReadOnly)
+        self.open(QIODevice.ReadOnly)
+    
+    def bytesAvailable(self):
+        """
+        Public method to get the number of available bytes.
+        
+        @return number of available bytes
+        @rtype int
+        """
+        return self.__buffer.bytesAvailable()
+    
+    def readData(self, maxlen):
+        """
+        Public method to retrieve data from the reply object.
+        
+        @param maxlen maximum number of bytes to read (integer)
+        @return string containing the data (bytes)
+        """
+        return self.__buffer.read(maxlen)
+    
+    def close(self):
+        """
+        Public method used to cloase the reply.
+        """
+        super(QtHelpSchemeReply, self).close()
+        self.closed.emit()
+    
+    def __mimeFromUrl(self, url):
+        """
+        Private method to guess the mime type given an URL.
+        
+        @param url URL to guess the mime type from (QUrl)
+        @return mime type for the given URL (string)
+        """
+        path = url.path()
+        ext = os.path.splitext(path)[1].lower()
+        if ext in ExtensionMap:
+            return ExtensionMap[ext]
+        else:
+            return "application/octet-stream"
+    
+    def mimeType(self):
+        """
+        Public method to get the reply mime type.
+        
+        @return mime type of the reply
+        @rtype bytes
+        """
+        return self.__mimeType.encode("utf-8")
+##
+##
+##
+##
+##
+##class QtHelpAccessHandler(SchemeAccessHandler):
+##    """
+##    Class implementing a scheme access handler for QtHelp.
+##    """
+##    def __init__(self, engine, parent=None):
+##        """
+##        Constructor
+##        
+##        @param engine reference to the help engine (QHelpEngine)
+##        @param parent reference to the parent object (QObject)
+##        """
+##        SchemeAccessHandler.__init__(self, parent)
+##        
+##        self.__engine = engine
+##    
+##    def __mimeFromUrl(self, url):
+##        """
+##        Private method to guess the mime type given an URL.
+##        
+##        @param url URL to guess the mime type from (QUrl)
+##        @return mime type for the given URL (string)
+##        """
+##        path = url.path()
+##        ext = os.path.splitext(path)[1].lower()
+##        if ext in ExtensionMap:
+##            return ExtensionMap[ext]
+##        else:
+##            return "application/octet-stream"
+##    
+##    def createRequest(self, op, request, outgoingData=None):
+##        """
+##        Public method to create a request.
+##        
+##        @param op the operation to be performed
+##            (QNetworkAccessManager.Operation)
+##        @param request reference to the request object (QNetworkRequest)
+##        @param outgoingData reference to an IODevice containing data to be sent
+##            (QIODevice)
+##        @return reference to the created reply object (QNetworkReply)
+##        """
+##        url = request.url()
+##        strUrl = url.toString()
+##        
+##        # For some reason the url to load is already wrong (passed from webkit)
+##        # though the css file and the references inside should work that way.
+##        # One possible problem might be that the css is loaded at the same
+##        # level as the html, thus a path inside the css like
+##        # (../images/foo.png) might cd out of the virtual folder
+##        if not self.__engine.findFile(url).isValid():
+##            if strUrl.startswith(QtDocPath):
+##                newUrl = request.url()
+##                if not newUrl.path().startswith("/qdoc/"):
+##                    newUrl.setPath("qdoc" + newUrl.path())
+##                    url = newUrl
+##                    strUrl = url.toString()
+##        
+##        mimeType = mimetypes.guess_type(strUrl)[0]
+##        if mimeType is None:
+##            # do our own (limited) guessing
+##            mimeType = self.__mimeFromUrl(url)
+##        
+##        if self.__engine.findFile(url).isValid():
+##            data = self.__engine.fileData(url)
+##        else:
+##            data = QByteArray(self.tr(
+##                """<title>Error 404...</title>"""
+##                """<div align="center"><br><br>"""
+##                """<h1>The page could not be found</h1><br>"""
+##                """<h3>'{0}'</h3></div>""").format(strUrl).encode("utf-8"))
+##        return NetworkReply(request, data, mimeType, self.parent())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/HelpDocsInstaller.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,245 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a thread class populating and updating the QtHelp
+documentation database.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import pyqtSignal, qVersion, QThread, Qt, QMutex, \
+    QDateTime, QDir, QLibraryInfo, QFileInfo
+from PyQt5.QtHelp import QHelpEngineCore
+
+from eric6config import getConfig
+
+
+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(HelpDocsInstaller, self).__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.LowPriority)
+    
+    def run(self):
+        """
+        Public method executed by the thread.
+        """
+        engine = QHelpEngineCore(self.__collection)
+        engine.setupData()
+        changes = False
+        
+        qt4Docs = ["designer", "linguist", "qt"]
+        qt5Docs = [
+            "activeqt", "qdoc", "qmake", "qt3d", "qt3drenderer",
+            "qtandroidextras", "qtassistant", "qtbluetooth", "qtcanvas3d",
+            "qtconcurrent", "qtcore", "qtdbus", "qtdesigner", "qtdoc",
+            "qtenginio", "qtenginiooverview", "qtenginoqml",
+            "qtgraphicaleffects", "qtgui", "qthelp", "qtimageformats",
+            "qtlabscontrols", "qtlinguist", "qtlocation", "qtmaxextras",
+            "qtmultimedia", "qtmultimediawidgets", "qtnetwork", "qtnfc",
+            "qtopengl", "qtplatformheaders", "qtpositioning", "qtprintsupport",
+            "qtqml", "qtquick", "qtquickcontrols", "qtquickdialogs",
+            "qtquickextras", "qtquicklayouts", "qtscript", "qtscripttools",
+            "qtsensors", "qtserialbus", "qtserialport", "qtsql", "qtsvg",
+            "qttestlib", "qtuitools", "qtwebchannel", "qtwebengine",
+            "qtwebenginewidgets", "qtwebkit", "qtwebkitexamples",
+            "qtwebsockets", "qtwebview", "qtwidgets", "qtwinextras",
+            "qtx11extras", "qtxml", "qtxmlpatterns"]
+        for qtDocs, version in [(qt4Docs, 4), (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.ISODate)
+        
+        qchFile = ""
+        if len(lst) == 2:
+            qchFile = lst[1]
+        
+        if version == 4:
+            docsPath = QDir(
+                QLibraryInfo.location(QLibraryInfo.DocumentationPath) +
+                QDir.separator() + "qch")
+        elif version == 5:
+            docsPath = QLibraryInfo.location(QLibraryInfo.DocumentationPath)
+            if not os.path.isdir(docsPath) or \
+                    len(QDir(docsPath).entryList(["*.qch"])) == 0:
+                # Qt installer is a bit buggy; it's missing a symbolic link
+                docsPathList = QDir.fromNativeSeparators(docsPath).split("/")
+                docsPath = os.sep.join(
+                    docsPathList[:-3] +
+                    ["Docs", "Qt-{0}".format(qVersion()[:3])])
+            docsPath = QDir(docsPath)
+        else:
+            # unsupported Qt version
+            return False
+        
+        files = docsPath.entryList(["*.qch"])
+        if not files:
+            engine.setCustomValue(
+                versionKey,
+                QDateTime().toString(Qt.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.ISODate) == \
+                    dt.toString(Qt.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.ISODate) + '|' +
+                    fi.absoluteFilePath())
+                return True
+        
+        return False
+    
+    def __installEric6Doc(self, engine):
+        """
+        Private method to install/update the eric6 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.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.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.ISODate) == \
+                    dt.toString(Qt.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.ISODate) + '|' +
+                    fi.absoluteFilePath())
+                return True
+        
+        return False
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/HelpIndexWidget.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a window for showing the QtHelp index.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSignal, Qt, QUrl, QEvent
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QLineEdit, QMenu, \
+    QDialog
+
+
+class HelpIndexWidget(QWidget):
+    """
+    Class implementing a window for showing the QtHelp index.
+    
+    @signal linkActivated(QUrl) emitted when an index entry is activated
+    @signal linksActivated(links, keyword) emitted when an index entry
+        referencing multiple targets is activated
+    @signal escapePressed() emitted when the ESC key was pressed
+    """
+    linkActivated = pyqtSignal(QUrl)
+    linksActivated = pyqtSignal(dict, str)
+    escapePressed = pyqtSignal()
+    
+    def __init__(self, engine, mainWindow, parent=None):
+        """
+        Constructor
+        
+        @param engine reference to the help engine (QHelpEngine)
+        @param mainWindow reference to the main window object (QMainWindow)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(HelpIndexWidget, self).__init__(parent)
+        
+        self.__engine = engine
+        self.__mw = mainWindow
+        
+        self.__searchEdit = None
+        self.__index = None
+        
+        self.__layout = QVBoxLayout(self)
+        label = QLabel(self.tr("&Look for:"))
+        self.__layout.addWidget(label)
+        
+        self.__searchEdit = QLineEdit()
+        label.setBuddy(self.__searchEdit)
+        self.__searchEdit.textChanged.connect(self.__filterIndices)
+        self.__searchEdit.installEventFilter(self)
+        self.__layout.addWidget(self.__searchEdit)
+        
+        self.__index = self.__engine.indexWidget()
+        self.__index.installEventFilter(self)
+        self.__engine.indexModel().indexCreationStarted.connect(
+            self.__disableSearchEdit)
+        self.__engine.indexModel().indexCreated.connect(
+            self.__enableSearchEdit)
+        self.__index.activated.connect(self.__activated)
+        self.__searchEdit.returnPressed.connect(
+            self.__index.activateCurrentItem)
+        self.__layout.addWidget(self.__index)
+        
+        self.__index.viewport().installEventFilter(self)
+    
+    def __activated(self, idx):
+        """
+        Private slot to handle the activation of a keyword entry.
+        
+        @param idx index of the activated entry (QModelIndex)
+        """
+        model = self.__index.model()
+        if model is not None:
+            keyword = model.data(idx, Qt.DisplayRole)
+            links = model.linksForKeyword(keyword)
+            if len(links) == 1:
+                self.linkActivated.emit(QUrl(links[list(links.keys())[0]]))
+            else:
+                self.linksActivated.emit(links, keyword)
+    
+    def __filterIndices(self, filter):
+        """
+        Private slot to filter the indices according to the given filter.
+        
+        @param filter filter to be used (string)
+        """
+        if '*' in filter:
+            self.__index.filterIndices(filter, filter)
+        else:
+            self.__index.filterIndices(filter)
+    
+    def __enableSearchEdit(self):
+        """
+        Private slot to enable the search edit.
+        """
+        self.__searchEdit.setEnabled(True)
+        self.__filterIndices(self.__searchEdit.text())
+    
+    def __disableSearchEdit(self):
+        """
+        Private slot to enable the search edit.
+        """
+        self.__searchEdit.setEnabled(False)
+    
+    def focusInEvent(self, evt):
+        """
+        Protected method handling focus in events.
+        
+        @param evt reference to the focus event object (QFocusEvent)
+        """
+        if evt.reason() != Qt.MouseFocusReason:
+            self.__searchEdit.selectAll()
+            self.__searchEdit.setFocus()
+    
+    def eventFilter(self, watched, event):
+        """
+        Public method called to filter the event queue.
+        
+        @param watched the QObject being watched (QObject)
+        @param event the event that occurred (QEvent)
+        @return flag indicating whether the event was handled (boolean)
+        """
+        if self.__searchEdit and watched == self.__searchEdit and \
+           event.type() == QEvent.KeyPress:
+            idx = self.__index.currentIndex()
+            if event.key() == Qt.Key_Up:
+                idx = self.__index.model().index(
+                    idx.row() - 1, idx.column(), idx.parent())
+                if idx.isValid():
+                    self.__index.setCurrentIndex(idx)
+            elif event.key() == Qt.Key_Down:
+                idx = self.__index.model().index(
+                    idx.row() + 1, idx.column(), idx.parent())
+                if idx.isValid():
+                    self.__index.setCurrentIndex(idx)
+            elif event.key() == Qt.Key_Escape:
+                self.escapePressed.emit()
+        elif self.__index and watched == self.__index and \
+                event.type() == QEvent.ContextMenu:
+            idx = self.__index.indexAt(event.pos())
+            if idx.isValid():
+                menu = QMenu()
+                curTab = menu.addAction(self.tr("Open Link"))
+                newTab = menu.addAction(self.tr("Open Link in New Tab"))
+                menu.move(self.__index.mapToGlobal(event.pos()))
+                
+                act = menu.exec_()
+                if act == curTab:
+                    self.__activated(idx)
+                elif act == newTab:
+                    model = self.__index.model()
+                    if model is not None:
+                        keyword = model.data(idx, Qt.DisplayRole)
+                        links = model.linksForKeyword(keyword)
+                        if len(links) == 1:
+                            self.__mw.newTab(list(links.values())[0])
+                        elif len(links) > 1:
+                            from .HelpTopicDialog import HelpTopicDialog
+                            dlg = HelpTopicDialog(self, keyword, links)
+                            if dlg.exec_() == QDialog.Accepted:
+                                self.__mw.newTab(dlg.link())
+        elif self.__index and watched == self.__index.viewport() and \
+                event.type() == QEvent.MouseButtonRelease:
+            idx = self.__index.indexAt(event.pos())
+            if idx.isValid() and event.button() == Qt.MidButton:
+                model = self.__index.model()
+                if model is not None:
+                    keyword = model.data(idx, Qt.DisplayRole)
+                    links = model.linksForKeyword(keyword)
+                    if len(links) == 1:
+                        self.__mw.newTab(list(links.values())[0])
+                    elif len(links) > 1:
+                        from .HelpTopicDialog import HelpTopicDialog
+                        dlg = HelpTopicDialog(self, keyword, links)
+                        if dlg.exec_() == QDialog.Accepted:
+                            self.__mw.newTab(dlg.link())
+        
+        return QWidget.eventFilter(self, watched, event)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/HelpSearchWidget.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a window for showing the QtHelp index.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSignal, Qt, QEvent, QUrl
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QTextBrowser, QApplication, \
+    QMenu
+
+
+class HelpSearchWidget(QWidget):
+    """
+    Class implementing a window for showing the QtHelp index.
+    
+    @signal linkActivated(QUrl) emitted when a search result entry is activated
+    @signal escapePressed() emitted when the ESC key was pressed
+    """
+    linkActivated = pyqtSignal(QUrl)
+    escapePressed = pyqtSignal()
+    
+    def __init__(self, engine, mainWindow, parent=None):
+        """
+        Constructor
+        
+        @param engine reference to the help search engine (QHelpSearchEngine)
+        @param mainWindow reference to the main window object (QMainWindow)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(HelpSearchWidget, self).__init__(parent)
+        
+        self.__engine = engine
+        self.__mw = mainWindow
+        
+        self.__layout = QVBoxLayout(self)
+        
+        self.__result = self.__engine.resultWidget()
+        self.__query = self.__engine.queryWidget()
+        
+        self.__layout.addWidget(self.__query)
+        self.__layout.addWidget(self.__result)
+        
+        self.setFocusProxy(self.__query)
+        
+        self.__query.search.connect(self.__search)
+        self.__result.requestShowLink.connect(self.linkActivated)
+        
+        self.__engine.searchingStarted.connect(self.__searchingStarted)
+        self.__engine.searchingFinished.connect(self.__searchingFinished)
+        
+        self.__browser = self.__result.findChildren(QTextBrowser)[0]
+        if self.__browser:
+            self.__browser.viewport().installEventFilter(self)
+    
+    def __search(self):
+        """
+        Private slot to perform a search of the database.
+        """
+        query = self.__query.query()
+        self.__engine.search(query)
+    
+    def __searchingStarted(self):
+        """
+        Private slot to handle the start of a search.
+        """
+        QApplication.setOverrideCursor(Qt.WaitCursor)
+    
+    def __searchingFinished(self, hits):
+        """
+        Private slot to handle the end of the search.
+        
+        @param hits number of hits (integer) (unused)
+        """
+        QApplication.restoreOverrideCursor()
+    
+    def eventFilter(self, watched, event):
+        """
+        Public method called to filter the event queue.
+        
+        @param watched the QObject being watched (QObject)
+        @param event the event that occurred (QEvent)
+        @return flag indicating whether the event was handled (boolean)
+        """
+        if self.__browser and watched == self.__browser.viewport() and \
+           event.type() == QEvent.MouseButtonRelease:
+            link = self.__result.linkAt(event.pos())
+            if not link.isEmpty() and link.isValid():
+                ctrl = event.modifiers() & Qt.ControlModifier
+                if (event.button() == Qt.LeftButton and ctrl) or \
+                   event.button() == Qt.MidButton:
+                    self.__mw.newTab(link)
+        
+        return QWidget.eventFilter(self, watched, event)
+    
+    def keyPressEvent(self, evt):
+        """
+        Protected method handling key press events.
+        
+        @param evt reference to the key press event (QKeyEvent)
+        """
+        if evt.key() == Qt.Key_Escape:
+            self.escapePressed.emit()
+        else:
+            evt.ignore()
+    
+    def contextMenuEvent(self, evt):
+        """
+        Protected method handling context menu events.
+        
+        @param evt reference to the context menu event (QContextMenuEvent)
+        """
+        point = evt.globalPos()
+        
+        if self.__browser:
+            point = self.__browser.mapFromGlobal(point)
+            if not self.__browser.rect().contains(point, True):
+                return
+            link = QUrl(self.__browser.anchorAt(point))
+        else:
+            point = self.__result.mapFromGlobal(point)
+            link = self.__result.linkAt(point)
+        
+        if link.isEmpty() or not link.isValid():
+            return
+        
+        menu = QMenu()
+        curTab = menu.addAction(self.tr("Open Link"))
+        newTab = menu.addAction(self.tr("Open Link in New Tab"))
+        menu.move(evt.globalPos())
+        act = menu.exec_()
+        if act == curTab:
+            self.linkActivated.emit(link)
+        elif act == newTab:
+            self.__mw.newTab(link)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/HelpTocWidget.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a window for showing the QtHelp TOC.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSignal, Qt, QEvent, QUrl
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QMenu
+
+
+class HelpTocWidget(QWidget):
+    """
+    Class implementing a window for showing the QtHelp TOC.
+    
+    @signal linkActivated(QUrl) emitted when a TOC entry is activated
+    @signal escapePressed() emitted when the ESC key was pressed
+    """
+    linkActivated = pyqtSignal(QUrl)
+    escapePressed = pyqtSignal()
+    
+    def __init__(self, engine, mainWindow, parent=None):
+        """
+        Constructor
+        
+        @param engine reference to the help engine (QHelpEngine)
+        @param mainWindow reference to the main window object (QMainWindow)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(HelpTocWidget, self).__init__(parent)
+        
+        self.__engine = engine
+        self.__mw = mainWindow
+        self.__expandDepth = -2
+        
+        self.__tocWidget = self.__engine.contentWidget()
+        self.__tocWidget.viewport().installEventFilter(self)
+        self.__tocWidget.setContextMenuPolicy(Qt.CustomContextMenu)
+        self.__tocWidget.setSortingEnabled(True)
+        
+        self.__layout = QVBoxLayout(self)
+        self.__layout.addWidget(self.__tocWidget)
+        
+        self.__tocWidget.customContextMenuRequested.connect(
+            self.__showContextMenu)
+        self.__tocWidget.linkActivated.connect(self.linkActivated)
+        
+        model = self.__tocWidget.model()
+        model.contentsCreated.connect(self.__contentsCreated)
+    
+    def __contentsCreated(self):
+        """
+        Private slot to be run after the contents was generated.
+        """
+        self.__tocWidget.sortByColumn(0, Qt.AscendingOrder)
+        self.__expandTOC()
+    
+    def __expandTOC(self):
+        """
+        Private slot to expand the table of contents.
+        """
+        if self.__expandDepth > -2:
+            self.expandToDepth(self.__expandDepth)
+            self.__expandDepth = -2
+    
+    def expandToDepth(self, depth):
+        """
+        Public slot to expand the table of contents to a specific depth.
+        
+        @param depth depth to expand to (integer)
+        """
+        self.__expandDepth = depth
+        if depth == -1:
+            self.__tocWidget.expandAll()
+        else:
+            self.__tocWidget.expandToDepth(depth)
+    
+    def focusInEvent(self, evt):
+        """
+        Protected method handling focus in events.
+        
+        @param evt reference to the focus event object (QFocusEvent)
+        """
+        if evt.reason() != Qt.MouseFocusReason:
+            self.__tocWidget.setFocus()
+    
+    def keyPressEvent(self, evt):
+        """
+        Protected method handling key press events.
+        
+        @param evt reference to the key press event (QKeyEvent)
+        """
+        if evt.key() == Qt.Key_Escape:
+            self.escapePressed.emit()
+    
+    def eventFilter(self, watched, event):
+        """
+        Public method called to filter the event queue.
+        
+        @param watched the QObject being watched (QObject)
+        @param event the event that occurred (QEvent)
+        @return flag indicating whether the event was handled (boolean)
+        """
+        if self.__tocWidget and watched == self.__tocWidget.viewport() and \
+           event.type() == QEvent.MouseButtonRelease:
+            if self.__tocWidget.indexAt(event.pos()).isValid() and \
+               event.button() == Qt.LeftButton:
+                self.itemClicked(self.__tocWidget.currentIndex())
+            elif self.__tocWidget.indexAt(event.pos()).isValid() and \
+                    event.button() == Qt.MidButton:
+                model = self.__tocWidget.model()
+                itm = model.contentItemAt(self.__tocWidget.currentIndex())
+                self.__mw.newTab(itm.url())
+        
+        return QWidget.eventFilter(self, watched, event)
+    
+    def itemClicked(self, index):
+        """
+        Public slot handling a click of a TOC entry.
+        
+        @param index index of the TOC clicked (QModelIndex)
+        """
+        if not index.isValid():
+            return
+        
+        model = self.__tocWidget.model()
+        itm = model.contentItemAt(index)
+        if itm:
+            self.linkActivated.emit(itm.url())
+    
+    def syncToContent(self, url):
+        """
+        Public method to sync the TOC to the displayed page.
+        
+        @param url URL of the displayed page (QUrl)
+        @return flag indicating a successful synchronization (boolean)
+        """
+        idx = self.__tocWidget.indexOf(url)
+        if not idx.isValid():
+            return False
+        self.__tocWidget.setCurrentIndex(idx)
+        return True
+    
+    def __showContextMenu(self, pos):
+        """
+        Private slot showing the context menu.
+        
+        @param pos position to show the menu at (QPoint)
+        """
+        if not self.__tocWidget.indexAt(pos).isValid():
+            return
+        
+        menu = QMenu()
+        curTab = menu.addAction(self.tr("Open Link"))
+        newTab = menu.addAction(self.tr("Open Link in New Tab"))
+        menu.move(self.__tocWidget.mapToGlobal(pos))
+        
+        model = self.__tocWidget.model()
+        itm = model.contentItemAt(self.__tocWidget.currentIndex())
+        
+        act = menu.exec_()
+        if act == curTab:
+            self.linkActivated.emit(itm.url())
+        elif act == newTab:
+            self.__mw.newTab(itm.url())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/HelpTopicDialog.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to select a help topic to display.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtWidgets import QDialog
+from PyQt5.QtCore import QUrl
+
+from .Ui_HelpTopicDialog import Ui_HelpTopicDialog
+
+
+class HelpTopicDialog(QDialog, Ui_HelpTopicDialog):
+    """
+    Class implementing a dialog to select a help topic to display.
+    """
+    def __init__(self, parent, keyword, links):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        @param keyword keyword for the link set (string)
+        @param links dictionary with help topic as key (string) and
+            URL as value (QUrl)
+        """
+        super(HelpTopicDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.label.setText(self.tr("Choose a &topic for <b>{0}</b>:")
+                           .format(keyword))
+        
+        self.__links = links
+        for topic in sorted(self.__links):
+            self.topicsList.addItem(topic)
+        if self.topicsList.count() > 0:
+            self.topicsList.setCurrentRow(0)
+        self.topicsList.setFocus()
+        
+        self.topicsList.itemActivated.connect(self.accept)
+    
+    def link(self):
+        """
+        Public method to the link of the selected topic.
+        
+        @return URL of the selected topic (QUrl)
+        """
+        itm = self.topicsList.currentItem()
+        if itm is None:
+            return QUrl()
+        
+        topic = itm.text()
+        if topic == "" or topic not in self.__links:
+            return QUrl()
+        
+        return self.__links[topic]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/HelpTopicDialog.ui	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,80 @@
+<ui version="4.0" >
+ <class>HelpTopicDialog</class>
+ <widget class="QDialog" name="HelpTopicDialog" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>500</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Select Help Topic</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout" >
+   <item>
+    <widget class="QLabel" name="label" >
+     <property name="text" >
+      <string>&amp;Topics:</string>
+     </property>
+     <property name="buddy" >
+      <cstring>topicsList</cstring>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QListWidget" name="topicsList" />
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox" >
+     <property name="orientation" >
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons" >
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>topicsList</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>HelpTopicDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>HelpTopicDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/QtHelpDocumentationDialog.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,155 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to manage the QtHelp documentation database.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel
+from PyQt5.QtWidgets import QDialog
+from PyQt5.QtHelp import QHelpEngineCore
+
+from E5Gui import E5MessageBox, E5FileDialog
+
+from .Ui_QtHelpDocumentationDialog import Ui_QtHelpDocumentationDialog
+
+
+class QtHelpDocumentationDialog(QDialog, Ui_QtHelpDocumentationDialog):
+    """
+    Class implementing a dialog to manage the QtHelp documentation database.
+    """
+    def __init__(self, engine, parent):
+        """
+        Constructor
+        
+        @param engine reference to the help engine (QHelpEngine)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(QtHelpDocumentationDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.removeButton.setEnabled(False)
+        
+        self.__engine = engine
+        self.__mw = parent
+        
+        docs = self.__engine.registeredDocumentations()
+        self.documentsList.addItems(docs)
+        
+        self.__registeredDocs = []
+        self.__unregisteredDocs = []
+        self.__tabsToClose = []
+    
+    @pyqtSlot()
+    def on_documentsList_itemSelectionChanged(self):
+        """
+        Private slot handling a change of the documents selection.
+        """
+        self.removeButton.setEnabled(
+            len(self.documentsList.selectedItems()) != 0)
+    
+    @pyqtSlot()
+    def on_addButton_clicked(self):
+        """
+        Private slot to add documents to the help database.
+        """
+        fileNames = E5FileDialog.getOpenFileNames(
+            self,
+            self.tr("Add Documentation"),
+            "",
+            self.tr("Qt Compressed Help Files (*.qch)"))
+        if not fileNames:
+            return
+        
+        for fileName in fileNames:
+            ns = QHelpEngineCore.namespaceName(fileName)
+            if not ns:
+                E5MessageBox.warning(
+                    self,
+                    self.tr("Add Documentation"),
+                    self.tr(
+                        """The file <b>{0}</b> is not a valid"""
+                        """ Qt Help File.""").format(fileName)
+                )
+                continue
+            
+            if len(self.documentsList.findItems(ns, Qt.MatchFixedString)):
+                E5MessageBox.warning(
+                    self,
+                    self.tr("Add Documentation"),
+                    self.tr(
+                        """The namespace <b>{0}</b> is already registered.""")
+                    .format(ns)
+                )
+                continue
+            
+            self.__engine.registerDocumentation(fileName)
+            self.documentsList.addItem(ns)
+            self.__registeredDocs.append(ns)
+            if ns in self.__unregisteredDocs:
+                self.__unregisteredDocs.remove(ns)
+
+    @pyqtSlot()
+    def on_removeButton_clicked(self):
+        """
+        Private slot to remove a document from the help database.
+        """
+        res = E5MessageBox.yesNo(
+            self,
+            self.tr("Remove Documentation"),
+            self.tr(
+                """Do you really want to remove the selected documentation """
+                """sets from the database?"""))
+        if not res:
+            return
+        
+        openedDocs = self.__mw.getSourceFileList()
+        
+        items = self.documentsList.selectedItems()
+        for item in items:
+            ns = item.text()
+            if ns in list(openedDocs.values()):
+                res = E5MessageBox.yesNo(
+                    self,
+                    self.tr("Remove Documentation"),
+                    self.tr(
+                        """Some documents currently opened reference the """
+                        """documentation you are attempting to remove. """
+                        """Removing the documentation will close those """
+                        """documents. Remove anyway?"""),
+                    icon=E5MessageBox.Warning)
+                if not res:
+                    return
+            self.__unregisteredDocs.append(ns)
+            for id in openedDocs:
+                if openedDocs[id] == ns and id not in self.__tabsToClose:
+                    self.__tabsToClose.append(id)
+            itm = self.documentsList.takeItem(self.documentsList.row(item))
+            del itm
+            
+            self.__engine.unregisterDocumentation(ns)
+        
+        if self.documentsList.count():
+            self.documentsList.setCurrentRow(
+                0, QItemSelectionModel.ClearAndSelect)
+    
+    def hasChanges(self):
+        """
+        Public slot to test the dialog for changes.
+        
+        @return flag indicating presence of changes
+        """
+        return len(self.__registeredDocs) > 0 or \
+            len(self.__unregisteredDocs) > 0
+    
+    def getTabsToClose(self):
+        """
+        Public method to get the list of tabs to close.
+        
+        @return list of tab ids to be closed (list of integers)
+        """
+        return self.__tabsToClose
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/QtHelpDocumentationDialog.ui	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtHelpDocumentationDialog</class>
+ <widget class="QDialog" name="QtHelpDocumentationDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>425</width>
+    <height>391</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Manage QtHelp Documentation Database</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Registered Documents</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0" rowspan="3">
+      <widget class="QListWidget" name="documentsList">
+       <property name="alternatingRowColors">
+        <bool>true</bool>
+       </property>
+       <property name="selectionMode">
+        <enum>QAbstractItemView::ExtendedSelection</enum>
+       </property>
+       <property name="sortingEnabled">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QPushButton" name="addButton">
+       <property name="toolTip">
+        <string>Press to select QtHelp documents to add to the database</string>
+       </property>
+       <property name="text">
+        <string>Add...</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QPushButton" name="removeButton">
+       <property name="toolTip">
+        <string>Press to remove the selected documents from the database</string>
+       </property>
+       <property name="text">
+        <string>Remove</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <spacer name="verticalSpacer">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>20</width>
+         <height>98</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>documentsList</tabstop>
+  <tabstop>addButton</tabstop>
+  <tabstop>removeButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>QtHelpDocumentationDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>QtHelpDocumentationDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/QtHelpFiltersDialog.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,273 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to manage the QtHelp filters.
+"""
+
+from __future__ import unicode_literals
+
+import sqlite3
+
+from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel
+from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QListWidgetItem, \
+    QInputDialog, QLineEdit
+from PyQt5.QtHelp import QHelpEngineCore
+
+from E5Gui import E5MessageBox
+
+from .Ui_QtHelpFiltersDialog import Ui_QtHelpFiltersDialog
+
+
+class QtHelpFiltersDialog(QDialog, Ui_QtHelpFiltersDialog):
+    """
+    Class implementing a dialog to manage the QtHelp filters.
+    """
+    def __init__(self, engine, parent=None):
+        """
+        Constructor
+        
+        @param engine reference to the help engine (QHelpEngine)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(QtHelpFiltersDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.removeButton.setEnabled(False)
+        self.removeAttributeButton.setEnabled(False)
+        
+        self.__engine = engine
+        
+        self.filtersList.clear()
+        self.attributesList.clear()
+        
+        help = QHelpEngineCore(self.__engine.collectionFile())
+        help.setupData()
+        
+        self.__removedFilters = []
+        self.__filterMap = {}
+        self.__filterMapBackup = {}
+        self.__removedAttributes = []
+        
+        for filter in help.customFilters():
+            atts = help.filterAttributes(filter)
+            self.__filterMapBackup[filter] = atts
+            if filter not in self.__filterMap:
+                self.__filterMap[filter] = atts
+        
+        self.filtersList.addItems(sorted(self.__filterMap.keys()))
+        for attr in help.filterAttributes():
+            QTreeWidgetItem(self.attributesList, [attr])
+        self.attributesList.sortItems(0, Qt.AscendingOrder)
+        
+        if self.__filterMap:
+            self.filtersList.setCurrentRow(0)
+    
+    @pyqtSlot(QListWidgetItem, QListWidgetItem)
+    def on_filtersList_currentItemChanged(self, current, previous):
+        """
+        Private slot to update the attributes depending on the current filter.
+        
+        @param current reference to the current item (QListWidgetitem)
+        @param previous reference to the previous current item
+            (QListWidgetItem)
+        """
+        checkedList = []
+        if current is not None:
+            checkedList = self.__filterMap[current.text()]
+        for index in range(0, self.attributesList.topLevelItemCount()):
+            itm = self.attributesList.topLevelItem(index)
+            if itm.text(0) in checkedList:
+                itm.setCheckState(0, Qt.Checked)
+            else:
+                itm.setCheckState(0, Qt.Unchecked)
+    
+    @pyqtSlot()
+    def on_filtersList_itemSelectionChanged(self):
+        """
+        Private slot handling a change of selected filters.
+        """
+        self.removeButton.setEnabled(
+            len(self.filtersList.selectedItems()) > 0)
+    
+    @pyqtSlot(QTreeWidgetItem, int)
+    def on_attributesList_itemChanged(self, item, column):
+        """
+        Private slot to handle a change of an attribute.
+        
+        @param item reference to the changed item (QTreeWidgetItem)
+        @param column column containing the change (integer)
+        """
+        if self.filtersList.currentItem() is None:
+            return
+        
+        filter = self.filtersList.currentItem().text()
+        if filter not in self.__filterMap:
+            return
+        
+        newAtts = []
+        for index in range(0, self.attributesList.topLevelItemCount()):
+            itm = self.attributesList.topLevelItem(index)
+            if itm.checkState(0) == Qt.Checked:
+                newAtts.append(itm.text(0))
+        self.__filterMap[filter] = newAtts
+    
+    @pyqtSlot()
+    def on_attributesList_itemSelectionChanged(self):
+        """
+        Private slot handling the selection of attributes.
+        """
+        self.removeAttributeButton.setEnabled(
+            len(self.attributesList.selectedItems()) != 0)
+    
+    @pyqtSlot()
+    def on_addButton_clicked(self):
+        """
+        Private slot to add a new filter.
+        """
+        filter, ok = QInputDialog.getText(
+            None,
+            self.tr("Add Filter"),
+            self.tr("Filter name:"),
+            QLineEdit.Normal)
+        if not filter:
+            return
+        
+        if filter not in self.__filterMap:
+            self.__filterMap[filter] = []
+            self.filtersList.addItem(filter)
+        
+        itm = self.filtersList.findItems(filter, Qt.MatchCaseSensitive)[0]
+        self.filtersList.setCurrentItem(itm)
+    
+    @pyqtSlot()
+    def on_removeButton_clicked(self):
+        """
+        Private slot to remove the selected filters.
+        """
+        ok = E5MessageBox.yesNo(
+            self,
+            self.tr("Remove Filters"),
+            self.tr(
+                """Do you really want to remove the selected filters """
+                """from the database?"""))
+        if not ok:
+            return
+        
+        items = self.filtersList.selectedItems()
+        for item in items:
+            itm = self.filtersList.takeItem(self.filtersList.row(item))
+            if itm is None:
+                continue
+            
+            del self.__filterMap[itm.text()]
+            self.__removedFilters.append(itm.text())
+            del itm
+        
+        if self.filtersList.count():
+            self.filtersList.setCurrentRow(
+                0, QItemSelectionModel.ClearAndSelect)
+    
+    @pyqtSlot()
+    def on_removeAttributeButton_clicked(self):
+        """
+        Private slot to remove the selected filter attributes.
+        """
+        ok = E5MessageBox.yesNo(
+            self,
+            self.tr("Remove Attributes"),
+            self.tr(
+                """Do you really want to remove the selected attributes """
+                """from the database?"""))
+        if not ok:
+            return
+        
+        items = self.attributesList.selectedItems()
+        for item in items:
+            itm = self.attributesList.takeTopLevelItem(
+                self.attributesList.indexOfTopLevelItem(item))
+            if itm is None:
+                continue
+            
+            attr = itm.text(0)
+            self.__removedAttributes.append(attr)
+            for filter in self.__filterMap:
+                if attr in self.__filterMap[filter]:
+                    self.__filterMap[filter].remove(attr)
+            
+            del itm
+    
+    @pyqtSlot()
+    def on_unusedAttributesButton_clicked(self):
+        """
+        Private slot to select all unused attributes.
+        """
+        # step 1: determine all used attributes
+        attributes = set()
+        for filter in self.__filterMap:
+            attributes |= set(self.__filterMap[filter])
+        
+        # step 2: select all unused attribute items
+        self.attributesList.clearSelection()
+        for row in range(self.attributesList.topLevelItemCount()):
+            itm = self.attributesList.topLevelItem(row)
+            if itm.text(0) not in attributes:
+                itm.setSelected(True)
+    
+    def __removeAttributes(self):
+        """
+        Private method to remove attributes from the Qt Help database.
+        """
+        try:
+            self.__db = sqlite3.connect(self.__engine.collectionFile())
+        except sqlite3.DatabaseError:
+            pass        # ignore database errors
+        
+        for attr in self.__removedAttributes:
+            self.__db.execute(
+                "DELETE FROM FilterAttributeTable WHERE Name = '{0}'"
+                .format(attr))
+        self.__db.commit()
+        self.__db.close()
+    
+    @pyqtSlot()
+    def on_buttonBox_accepted(self):
+        """
+        Private slot to update the database, if the dialog is accepted.
+        """
+        filtersChanged = False
+        if len(self.__filterMapBackup) != len(self.__filterMap):
+            filtersChanged = True
+        else:
+            for filter in self.__filterMapBackup:
+                if filter not in self.__filterMap:
+                    filtersChanged = True
+                else:
+                    oldFilterAtts = self.__filterMapBackup[filter]
+                    newFilterAtts = self.__filterMap[filter]
+                    if len(oldFilterAtts) != len(newFilterAtts):
+                        filtersChanged = True
+                    else:
+                        for attr in oldFilterAtts:
+                            if attr not in newFilterAtts:
+                                filtersChanged = True
+                                break
+                
+                if filtersChanged:
+                    break
+        
+        if filtersChanged:
+            for filter in self.__removedFilters:
+                self.__engine.removeCustomFilter(filter)
+            for filter in self.__filterMap:
+                self.__engine.addCustomFilter(filter, self.__filterMap[filter])
+        
+        if self.__removedAttributes:
+            self.__removeAttributes()
+        
+        if filtersChanged or self.__removedAttributes:
+            self.__engine.setupData()
+        
+        self.accept()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/QtHelpFiltersDialog.ui	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtHelpFiltersDialog</class>
+ <widget class="QDialog" name="QtHelpFiltersDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>570</width>
+    <height>391</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Manage QtHelp Filters</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0" colspan="2">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Filters:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2" colspan="2">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Attributes:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0" colspan="2">
+      <widget class="QListWidget" name="filtersList">
+       <property name="alternatingRowColors">
+        <bool>true</bool>
+       </property>
+       <property name="selectionMode">
+        <enum>QAbstractItemView::ExtendedSelection</enum>
+       </property>
+       <property name="sortingEnabled">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2" colspan="2">
+      <widget class="QTreeWidget" name="attributesList">
+       <property name="alternatingRowColors">
+        <bool>true</bool>
+       </property>
+       <property name="selectionMode">
+        <enum>QAbstractItemView::ExtendedSelection</enum>
+       </property>
+       <property name="rootIsDecorated">
+        <bool>false</bool>
+       </property>
+       <property name="sortingEnabled">
+        <bool>true</bool>
+       </property>
+       <property name="headerHidden">
+        <bool>true</bool>
+       </property>
+       <column>
+        <property name="text">
+         <string>1</string>
+        </property>
+       </column>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QPushButton" name="addButton">
+       <property name="toolTip">
+        <string>Press to add a new filter</string>
+       </property>
+       <property name="text">
+        <string>Add Filter ...</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QPushButton" name="removeButton">
+       <property name="toolTip">
+        <string>Press to remove the selected filters</string>
+       </property>
+       <property name="text">
+        <string>Remove Filters</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="2">
+      <widget class="QPushButton" name="removeAttributeButton">
+       <property name="toolTip">
+        <string>Press to remove the selected attributes</string>
+       </property>
+       <property name="text">
+        <string>Remove Attributes</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="3">
+      <widget class="QPushButton" name="unusedAttributesButton">
+       <property name="statusTip">
+        <string>Press to select all unused attributes</string>
+       </property>
+       <property name="text">
+        <string>Select Unused</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>filtersList</tabstop>
+  <tabstop>addButton</tabstop>
+  <tabstop>removeButton</tabstop>
+  <tabstop>attributesList</tabstop>
+  <tabstop>removeAttributeButton</tabstop>
+  <tabstop>unusedAttributesButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>QtHelpFiltersDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>320</x>
+     <y>386</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/QtHelp/__init__.py	Sat Mar 19 16:05:11 2016 +0100
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package containing the interface to QtHelp.
+"""
--- a/WebBrowser/WebBrowserWindow.py	Sat Mar 19 12:13:09 2016 +0100
+++ b/WebBrowser/WebBrowserWindow.py	Sat Mar 19 16:05:11 2016 +0100
@@ -86,7 +86,7 @@
     _webProfile = None
     _networkManager = None
     _cookieJar = None
-##    _helpEngine = None
+    _helpEngine = None
     _bookmarksManager = None
     _historyManager = None
     _passwordManager = None
@@ -104,7 +104,7 @@
     
     def __init__(self, home, path, parent, name, fromEric=False,
                  initShortcutsOnly=False, searchWord=None,
-                 private=False, settingsDir=""):
+                 private=False, qthelp=False, settingsDir=""):
         """
         Constructor
         
@@ -118,6 +118,7 @@
             keyboard shortcuts (boolean)
         @keyparam searchWord word to search for (string)
         @keyparam private flag indicating a private browsing window (bool)
+        @keyparam qthelp flag indicating to enable the QtHelp support (bool)
         @keyparam settingsDir directory to be used for the settings files (str)
         """
         super(WebBrowserWindow, self).__init__(parent)
@@ -146,22 +147,21 @@
                     "QTWEBENGINE_REMOTE_DEBUGGING",
                     str(Preferences.getWebBrowser("WebInspectorPort")))
             
+            WebBrowserWindow.setUseQtHelp(
+                self.__fromEric or qthelp or bool(searchWord))
+            
             self.webProfile(private)
             self.networkManager()
             
             from .SearchWidget import SearchWidget
-            # TODO: QtHelp
-##            from .HelpTocWidget import HelpTocWidget
-##            from .HelpIndexWidget import HelpIndexWidget
-##            from .HelpSearchWidget import HelpSearchWidget
+            from .QtHelp.HelpTocWidget import HelpTocWidget
+            from .QtHelp.HelpIndexWidget import HelpIndexWidget
+            from .QtHelp.HelpSearchWidget import HelpSearchWidget
             from .WebBrowserView import WebBrowserView
             from .WebBrowserTabWidget import WebBrowserTabWidget
             from .AdBlock.AdBlockIcon import AdBlockIcon
             from .VirusTotal.VirusTotalApi import VirusTotalAPI
             
-            # TODO: allow using Qt Help even if not called from eric6
-            WebBrowserWindow.setUseQtHelp(self.__fromEric)
-            
             if not self.__fromEric:
                 self.setStyle(Preferences.getUI("Style"),
                               Preferences.getUI("StyleSheet"))
@@ -171,16 +171,16 @@
 ##                from E5Network.E5SslUtilities import initSSL
 ##                initSSL()
             
-            # TODO: QtHelp
-##            if WebBrowserWindow.UseQtHelp:
-##                self.__helpEngine = \
-##                    QHelpEngine(os.path.join(Utilities.getConfigDir(),
-##                                             "web_browser", "eric6help.qhc"), self)
-##                self.__removeOldDocumentation()
-##                self.__helpEngine.warning.connect(self.__warning)
-##            else:
-##                self.__helpEngine = None
-##            self.__helpInstaller = None
+            if WebBrowserWindow.useQtHelp:
+                self.__helpEngine = QHelpEngine(
+                    os.path.join(Utilities.getConfigDir(),
+                                 "web_browser", "eric6help.qhc"),
+                    self)
+                self.__removeOldDocumentation()
+                self.__helpEngine.warning.connect(self.__warning)
+            else:
+                self.__helpEngine = None
+            self.__helpInstaller = None
             
             self.__zoomWidget = E5ZoomWidget(
                 UI.PixmapCache.getPixmap("zoomOut.png"),
@@ -210,38 +210,38 @@
             self.setCentralWidget(centralWidget)
             self.__searchWidget.hide()
             
-            # TODO: QtHelp, do these once Qt 5.6 is available
-##            if WebBrowserWindow.UseQtHelp:
-##                # setup the TOC widget
-##                self.__tocWindow = HelpTocWidget(self.__helpEngine, self)
-##                self.__tocDock = QDockWidget(self.tr("Contents"), self)
-##                self.__tocDock.setObjectName("TocWindow")
-##                self.__tocDock.setWidget(self.__tocWindow)
-##                self.addDockWidget(Qt.LeftDockWidgetArea, self.__tocDock)
-##                
-##                # setup the index widget
-##                self.__indexWindow = HelpIndexWidget(self.__helpEngine, self)
-##                self.__indexDock = QDockWidget(self.tr("Index"), self)
-##                self.__indexDock.setObjectName("IndexWindow")
-##                self.__indexDock.setWidget(self.__indexWindow)
-##                self.addDockWidget(Qt.LeftDockWidgetArea, self.__indexDock)
-##                
-##                # setup the search widget
-##                self.__searchWord = searchWord
-##                self.__indexing = False
-##                self.__indexingProgress = None
-##                self.__searchEngine = self.__helpEngine.searchEngine()
-##                self.__searchEngine.indexingStarted.connect(
-##                    self.__indexingStarted)
-##                self.__searchEngine.indexingFinished.connect(
-##                    self.__indexingFinished)
-##                self.__searchWindow = HelpSearchWidget(
-##                    self.__searchEngine, self)
-##                self.__searchDock = QDockWidget(self.tr("Search"), self)
-##                self.__searchDock.setObjectName("SearchWindow")
-##                self.__searchDock.setWidget(self.__searchWindow)
-##                self.addDockWidget(Qt.LeftDockWidgetArea, self.__searchDock)
-##            
+            if WebBrowserWindow.useQtHelp:
+                # TODO: QtHelp: place the widgets in a tab widget
+                # setup the TOC widget
+                self.__tocWindow = HelpTocWidget(self.__helpEngine, self)
+                self.__tocDock = QDockWidget(self.tr("Contents"), self)
+                self.__tocDock.setObjectName("TocWindow")
+                self.__tocDock.setWidget(self.__tocWindow)
+                self.addDockWidget(Qt.LeftDockWidgetArea, self.__tocDock)
+                
+                # setup the index widget
+                self.__indexWindow = HelpIndexWidget(self.__helpEngine, self)
+                self.__indexDock = QDockWidget(self.tr("Index"), self)
+                self.__indexDock.setObjectName("IndexWindow")
+                self.__indexDock.setWidget(self.__indexWindow)
+                self.addDockWidget(Qt.LeftDockWidgetArea, self.__indexDock)
+                
+                # setup the search widget
+                self.__searchWord = searchWord
+                self.__indexing = False
+                self.__indexingProgress = None
+                self.__searchEngine = self.__helpEngine.searchEngine()
+                self.__searchEngine.indexingStarted.connect(
+                    self.__indexingStarted)
+                self.__searchEngine.indexingFinished.connect(
+                    self.__indexingFinished)
+                self.__searchWindow = HelpSearchWidget(
+                    self.__searchEngine, self)
+                self.__searchDock = QDockWidget(self.tr("Search"), self)
+                self.__searchDock.setObjectName("SearchWindow")
+                self.__searchDock.setWidget(self.__searchWindow)
+                self.addDockWidget(Qt.LeftDockWidgetArea, self.__searchDock)
+            
             # JavaScript Console window
             from .WebBrowserJavaScriptConsole import \
                 WebBrowserJavaScriptConsole
@@ -303,29 +303,27 @@
             
             # setup connections
             self.__activating = False
-            # TODO: QtHelp, do these once Qt 5.6 is available
-##            if WebBrowserWindow.UseQtHelp:
-##                # TOC window
-##                self.__tocWindow.linkActivated.connect(self.__linkActivated)
-##                self.__tocWindow.escapePressed.connect(
-##                    self.__activateCurrentBrowser)
-##                # index window
-##                self.__indexWindow.linkActivated.connect(self.__linkActivated)
-##                self.__indexWindow.linksActivated.connect(
-##                    self.__linksActivated)
-##                self.__indexWindow.escapePressed.connect(
-##                    self.__activateCurrentBrowser)
-##                # search window
-##                self.__searchWindow.linkActivated.connect(
-##                    self.__linkActivated)
-##                self.__searchWindow.escapePressed.connect(
-##                    self.__activateCurrentBrowser)
+            if WebBrowserWindow.useQtHelp:
+                # TOC window
+                self.__tocWindow.linkActivated.connect(self.__linkActivated)
+                self.__tocWindow.escapePressed.connect(
+                    self.__activateCurrentBrowser)
+                # index window
+                self.__indexWindow.linkActivated.connect(self.__linkActivated)
+                self.__indexWindow.linksActivated.connect(
+                    self.__linksActivated)
+                self.__indexWindow.escapePressed.connect(
+                    self.__activateCurrentBrowser)
+                # search window
+                self.__searchWindow.linkActivated.connect(
+                    self.__linkActivated)
+                self.__searchWindow.escapePressed.connect(
+                    self.__activateCurrentBrowser)
             
             state = Preferences.getWebBrowser("WebBrowserState")
             self.restoreState(state)
             
-            # TODO: QtHelp
-##            self.__initHelpDb()
+            self.__initHelpDb()
             
             self.__virusTotal = VirusTotalAPI(self)
             self.__virusTotal.submitUrlError.connect(
@@ -339,12 +337,11 @@
             
             self.flashCookieManager()
             
-            # TODO: QtHelp, do these once Qt 5.6 is available
-##            if WebBrowserWindow.UseQtHelp:
-##                QTimer.singleShot(0, self.__lookForNewDocumentation)
-##                if self.__searchWord is not None:
-##                    QTimer.singleShot(0, self.__searchForWord)
-##            
+            if WebBrowserWindow.useQtHelp:
+                QTimer.singleShot(0, self.__lookForNewDocumentation)
+                if self.__searchWord is not None:
+                    QTimer.singleShot(0, self.__searchForWord)
+            
             self.__lastActiveWindow = None
             e5App().focusChanged[QWidget, QWidget].connect(
                 self.__appFocusChanged)
@@ -487,6 +484,7 @@
             settings.setAttribute(
                 QWebEngineSettings.LocalStorageEnabled,
                 Preferences.getWebBrowser("LocalStorageEnabled"))
+        # TODO: Local Storage
 ##        localStorageDir = os.path.join(
 ##            Utilities.getConfigDir(), "web_browser", "weblocalstorage")
 ##        if not os.path.exists(localStorageDir):
@@ -516,8 +514,6 @@
         settings.setAttribute(
             QWebEngineSettings.XSSAuditingEnabled,
             Preferences.getWebBrowser("XSSAuditingEnabled"))
-##        
-##        QWebSecurityOrigin.addLocalScheme("eric")
         settings.setAttribute(
             QWebEngineSettings.ScrollAnimatorEnabled,
             Preferences.getWebBrowser("ScrollAnimatorEnabled"))
@@ -1383,112 +1379,111 @@
                 self.__showFeaturePermissionDialog)
         self.__actions.append(self.featurePermissionAct)
         
-        # TODO: QtHelp: re-enable once Qt 5.6 is available
-##        if WebBrowserWindow.UseQtHelp or self.__initShortcutsOnly:
-##            self.syncTocAct = E5Action(
-##                self.tr('Sync with Table of Contents'),
-##                UI.PixmapCache.getIcon("syncToc.png"),
-##                self.tr('Sync with Table of Contents'),
-##                0, 0, self, 'webbrowser_sync_toc')
-##            self.syncTocAct.setStatusTip(self.tr(
-##                'Synchronizes the table of contents with current page'))
-##            self.syncTocAct.setWhatsThis(self.tr(
-##                """<b>Sync with Table of Contents</b>"""
-##                """<p>Synchronizes the table of contents with current"""
-##                """ page.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.syncTocAct.triggered.connect(self.__syncTOC)
-##            self.__actions.append(self.syncTocAct)
-##            
-##            self.showTocAct = E5Action(
-##                self.tr('Table of Contents'),
-##                self.tr('Table of Contents'),
-##                0, 0, self, 'webbrowser_show_toc')
-##            self.showTocAct.setStatusTip(self.tr(
-##                'Shows the table of contents window'))
-##            self.showTocAct.setWhatsThis(self.tr(
-##                """<b>Table of Contents</b>"""
-##                """<p>Shows the table of contents window.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.showTocAct.triggered.connect(self.__showTocWindow)
-##            self.__actions.append(self.showTocAct)
-##            
-##            self.showIndexAct = E5Action(
-##                self.tr('Index'),
-##                self.tr('Index'),
-##                0, 0, self, 'webbrowser_show_index')
-##            self.showIndexAct.setStatusTip(self.tr(
-##                'Shows the index window'))
-##            self.showIndexAct.setWhatsThis(self.tr(
-##                """<b>Index</b>"""
-##                """<p>Shows the index window.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.showIndexAct.triggered.connect(self.__showIndexWindow)
-##            self.__actions.append(self.showIndexAct)
-##            
-##            self.showSearchAct = E5Action(
-##                self.tr('Search'),
-##                self.tr('Search'),
-##                0, 0, self, 'webbrowser_show_search')
-##            self.showSearchAct.setStatusTip(self.tr(
-##                'Shows the search window'))
-##            self.showSearchAct.setWhatsThis(self.tr(
-##                """<b>Search</b>"""
-##                """<p>Shows the search window.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.showSearchAct.triggered.connect(
-##                    self.__showSearchWindow)
-##            self.__actions.append(self.showSearchAct)
-##            
-##            self.manageQtHelpDocsAct = E5Action(
-##                self.tr('Manage QtHelp Documents'),
-##                self.tr('Manage QtHelp &Documents'),
-##                0, 0, self, 'webbrowser_qthelp_documents')
-##            self.manageQtHelpDocsAct.setStatusTip(self.tr(
-##                'Shows a dialog to manage the QtHelp documentation set'))
-##            self.manageQtHelpDocsAct.setWhatsThis(self.tr(
-##                """<b>Manage QtHelp Documents</b>"""
-##                """<p>Shows a dialog to manage the QtHelp documentation"""
-##                """ set.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.manageQtHelpDocsAct.triggered.connect(
-##                    self.__manageQtHelpDocumentation)
-##            self.__actions.append(self.manageQtHelpDocsAct)
-##            
-##            self.manageQtHelpFiltersAct = E5Action(
-##                self.tr('Manage QtHelp Filters'),
-##                self.tr('Manage QtHelp &Filters'),
-##                0, 0, self, 'webbrowser_qthelp_filters')
-##            self.manageQtHelpFiltersAct.setStatusTip(self.tr(
-##                'Shows a dialog to manage the QtHelp filters'))
-##            self.manageQtHelpFiltersAct.setWhatsThis(self.tr(
-##                """<b>Manage QtHelp Filters</b>"""
-##                """<p>Shows a dialog to manage the QtHelp filters.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.manageQtHelpFiltersAct.triggered.connect(
-##                    self.__manageQtHelpFilters)
-##            self.__actions.append(self.manageQtHelpFiltersAct)
-##            
-##            self.reindexDocumentationAct = E5Action(
-##                self.tr('Reindex Documentation'),
-##                self.tr('&Reindex Documentation'),
-##                0, 0, self, 'webbrowser_qthelp_reindex')
-##            self.reindexDocumentationAct.setStatusTip(self.tr(
-##                'Reindexes the documentation set'))
-##            self.reindexDocumentationAct.setWhatsThis(self.tr(
-##                """<b>Reindex Documentation</b>"""
-##                """<p>Reindexes the documentation set.</p>"""
-##            ))
-##            if not self.__initShortcutsOnly:
-##                self.reindexDocumentationAct.triggered.connect(
-##                    self.__searchEngine.reindexDocumentation)
-##            self.__actions.append(self.reindexDocumentationAct)
+        if WebBrowserWindow.useQtHelp or self.__initShortcutsOnly:
+            self.syncTocAct = E5Action(
+                self.tr('Sync with Table of Contents'),
+                UI.PixmapCache.getIcon("syncToc.png"),
+                self.tr('Sync with Table of Contents'),
+                0, 0, self, 'webbrowser_sync_toc')
+            self.syncTocAct.setStatusTip(self.tr(
+                'Synchronizes the table of contents with current page'))
+            self.syncTocAct.setWhatsThis(self.tr(
+                """<b>Sync with Table of Contents</b>"""
+                """<p>Synchronizes the table of contents with current"""
+                """ page.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.syncTocAct.triggered.connect(self.__syncTOC)
+            self.__actions.append(self.syncTocAct)
+            
+            self.showTocAct = E5Action(
+                self.tr('Table of Contents'),
+                self.tr('Table of Contents'),
+                0, 0, self, 'webbrowser_show_toc')
+            self.showTocAct.setStatusTip(self.tr(
+                'Shows the table of contents window'))
+            self.showTocAct.setWhatsThis(self.tr(
+                """<b>Table of Contents</b>"""
+                """<p>Shows the table of contents window.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.showTocAct.triggered.connect(self.__showTocWindow)
+            self.__actions.append(self.showTocAct)
+            
+            self.showIndexAct = E5Action(
+                self.tr('Index'),
+                self.tr('Index'),
+                0, 0, self, 'webbrowser_show_index')
+            self.showIndexAct.setStatusTip(self.tr(
+                'Shows the index window'))
+            self.showIndexAct.setWhatsThis(self.tr(
+                """<b>Index</b>"""
+                """<p>Shows the index window.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.showIndexAct.triggered.connect(self.__showIndexWindow)
+            self.__actions.append(self.showIndexAct)
+            
+            self.showSearchAct = E5Action(
+                self.tr('Search'),
+                self.tr('Search'),
+                0, 0, self, 'webbrowser_show_search')
+            self.showSearchAct.setStatusTip(self.tr(
+                'Shows the search window'))
+            self.showSearchAct.setWhatsThis(self.tr(
+                """<b>Search</b>"""
+                """<p>Shows the search window.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.showSearchAct.triggered.connect(
+                    self.__showSearchWindow)
+            self.__actions.append(self.showSearchAct)
+            
+            self.manageQtHelpDocsAct = E5Action(
+                self.tr('Manage QtHelp Documents'),
+                self.tr('Manage QtHelp &Documents'),
+                0, 0, self, 'webbrowser_qthelp_documents')
+            self.manageQtHelpDocsAct.setStatusTip(self.tr(
+                'Shows a dialog to manage the QtHelp documentation set'))
+            self.manageQtHelpDocsAct.setWhatsThis(self.tr(
+                """<b>Manage QtHelp Documents</b>"""
+                """<p>Shows a dialog to manage the QtHelp documentation"""
+                """ set.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.manageQtHelpDocsAct.triggered.connect(
+                    self.__manageQtHelpDocumentation)
+            self.__actions.append(self.manageQtHelpDocsAct)
+            
+            self.manageQtHelpFiltersAct = E5Action(
+                self.tr('Manage QtHelp Filters'),
+                self.tr('Manage QtHelp &Filters'),
+                0, 0, self, 'webbrowser_qthelp_filters')
+            self.manageQtHelpFiltersAct.setStatusTip(self.tr(
+                'Shows a dialog to manage the QtHelp filters'))
+            self.manageQtHelpFiltersAct.setWhatsThis(self.tr(
+                """<b>Manage QtHelp Filters</b>"""
+                """<p>Shows a dialog to manage the QtHelp filters.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.manageQtHelpFiltersAct.triggered.connect(
+                    self.__manageQtHelpFilters)
+            self.__actions.append(self.manageQtHelpFiltersAct)
+            
+            self.reindexDocumentationAct = E5Action(
+                self.tr('Reindex Documentation'),
+                self.tr('&Reindex Documentation'),
+                0, 0, self, 'webbrowser_qthelp_reindex')
+            self.reindexDocumentationAct.setStatusTip(self.tr(
+                'Reindexes the documentation set'))
+            self.reindexDocumentationAct.setWhatsThis(self.tr(
+                """<b>Reindex Documentation</b>"""
+                """<p>Reindexes the documentation set.</p>"""
+            ))
+            if not self.__initShortcutsOnly:
+                self.reindexDocumentationAct.triggered.connect(
+                    self.__searchEngine.reindexDocumentation)
+            self.__actions.append(self.reindexDocumentationAct)
         
         self.clearPrivateDataAct = E5Action(
             self.tr('Clear private data'),
@@ -1861,10 +1856,9 @@
         menu.addSeparator()
         menu.addAction(self.stopAct)
         menu.addAction(self.reloadAct)
-        # TODO: QtHelp
-##        if WebBrowserWindow.UseQtHelp:
-##            menu.addSeparator()
-##            menu.addAction(self.syncTocAct)
+        if WebBrowserWindow.useQtHelp:
+            menu.addSeparator()
+            menu.addAction(self.syncTocAct)
         
         from .History.HistoryMenu import HistoryMenu
         self.historyMenu = HistoryMenu(self, self.__tabWidget)
@@ -1930,12 +1924,11 @@
 ##        menu.addAction(self.userAgentManagerAct)
 ##        menu.addSeparator()
         
-        # TODO: QtHelp
-##        if WebBrowserWindow.UseQtHelp:
-##            menu.addAction(self.manageQtHelpDocsAct)
-##            menu.addAction(self.manageQtHelpFiltersAct)
-##            menu.addAction(self.reindexDocumentationAct)
-##            menu.addSeparator()
+        if WebBrowserWindow.useQtHelp:
+            menu.addAction(self.manageQtHelpDocsAct)
+            menu.addAction(self.manageQtHelpFiltersAct)
+            menu.addAction(self.reindexDocumentationAct)
+            menu.addSeparator()
         menu.addAction(self.clearPrivateDataAct)
         menu.addAction(self.clearIconsAct)
         
@@ -1953,11 +1946,11 @@
         menu.setTearOffEnabled(True)
         menu.addAction(self.showDownloadManagerAct)
         menu.addAction(self.showJavaScriptConsoleAct)
-##        if WebBrowserWindow.UseQtHelp:
-##            menu.addSeparator()
-##            menu.addAction(self.showTocAct)
-##            menu.addAction(self.showIndexAct)
-##            menu.addAction(self.showSearchAct)
+        if WebBrowserWindow.useQtHelp:
+            menu.addSeparator()
+            menu.addAction(self.showTocAct)
+            menu.addAction(self.showIndexAct)
+            menu.addAction(self.showSearchAct)
         
         mb.addSeparator()
         
@@ -2027,19 +2020,18 @@
         findtb.addAction(self.findNextAct)
         findtb.addAction(self.findPrevAct)
         
-        # TODO: QtHelp
-##        if WebBrowserWindow.UseQtHelp:
-##            filtertb = self.addToolBar(self.tr("Filter"))
-##            filtertb.setObjectName("FilterToolBar")
-##            self.filterCombo = QComboBox()
-##            self.filterCombo.setMinimumWidth(
-##                QFontMetrics(QFont()).width("ComboBoxWithEnoughWidth"))
-##            filtertb.addWidget(QLabel(self.tr("Filtered by: ")))
-##            filtertb.addWidget(self.filterCombo)
-##            self.__helpEngine.setupFinished.connect(self.__setupFilterCombo)
-##            self.filterCombo.activated[str].connect(
-##                self.__filterQtHelpDocumentation)
-##            self.__setupFilterCombo()
+        if WebBrowserWindow.useQtHelp:
+            filtertb = self.addToolBar(self.tr("Filter"))
+            filtertb.setObjectName("FilterToolBar")
+            self.filterCombo = QComboBox()
+            self.filterCombo.setMinimumWidth(
+                QFontMetrics(QFont()).width("ComboBoxWithEnoughWidth"))
+            filtertb.addWidget(QLabel(self.tr("Filtered by: ")))
+            filtertb.addWidget(self.filterCombo)
+            self.__helpEngine.setupFinished.connect(self.__setupFilterCombo)
+            self.filterCombo.activated[str].connect(
+                self.__filterQtHelpDocumentation)
+            self.__setupFilterCombo()
         
         settingstb = self.addToolBar(self.tr("Settings"))
         settingstb.setObjectName("SettingsToolBar")
@@ -2571,14 +2563,13 @@
         
         self.searchEdit.openSearchManager().close()
         
-        # TODO: QtHelp
-##        if WebBrowserWindow.UseQtHelp:
-##            self.__searchEngine.cancelIndexing()
-##            self.__searchEngine.cancelSearching()
-##            
-##            if self.__helpInstaller:
-##                self.__helpInstaller.stop()
-##        
+        if WebBrowserWindow.useQtHelp:
+            self.__searchEngine.cancelIndexing()
+            self.__searchEngine.cancelSearching()
+            
+            if self.__helpInstaller:
+                self.__helpInstaller.stop()
+        
         self.searchEdit.saveSearches()
         
         self.__tabWidget.closeAllBrowsers(shutdown=True)
@@ -2906,23 +2897,22 @@
         else:
             cls.useQtHelp = False
     
-    # TODO: QtHelp
-##    @classmethod
-##    def helpEngine(cls):
-##        """
-##        Class method to get a reference to the help engine.
-##        
-##        @return reference to the help engine (QHelpEngine)
-##        """
-##        if cls.useQtHelp:
-##            if cls._helpEngine is None:
-##                cls._helpEngine = \
-##                    QHelpEngine(os.path.join(Utilities.getConfigDir(),
-##                                             "web_browser", "eric6help.qhc"))
-##            return cls._helpEngine
-##        else:
-##            return None
-##        
+    @classmethod
+    def helpEngine(cls):
+        """
+        Class method to get a reference to the help engine.
+        
+        @return reference to the help engine (QHelpEngine)
+        """
+        if cls.useQtHelp:
+            if cls._helpEngine is None:
+                cls._helpEngine = \
+                    QHelpEngine(os.path.join(Utilities.getConfigDir(),
+                                             "web_browser", "eric6help.qhc"))
+            return cls._helpEngine
+        else:
+            return None
+        
     @classmethod
     def networkManager(cls):
         """
@@ -2932,7 +2922,7 @@
         """
         if cls._networkManager is None:
             from .Network.NetworkManager import NetworkManager
-            cls._networkManager = NetworkManager()
+            cls._networkManager = NetworkManager(cls.helpEngine())
         
         return cls._networkManager
     
@@ -2973,50 +2963,48 @@
             self.currentBrowser().setUrl(url)
             self.__activating = False
         
-    # TODO: QtHelp
-##    def __linksActivated(self, links, keyword):
-##        """
-##        Private slot to select a topic to be shown.
-##        
-##        @param links dictionary with help topic as key (string) and
-##            URL as value (QUrl)
-##        @param keyword keyword for the link set (string)
-##        """
-##        if not self.__activating:
-##            from .HelpTopicDialog import HelpTopicDialog
-##            self.__activating = True
-##            dlg = HelpTopicDialog(self, keyword, links)
-##            if dlg.exec_() == QDialog.Accepted:
-##                self.currentBrowser().setSource(dlg.link())
-##            self.__activating = False
-##    
+    def __linksActivated(self, links, keyword):
+        """
+        Private slot to select a topic to be shown.
+        
+        @param links dictionary with help topic as key (string) and
+            URL as value (QUrl)
+        @param keyword keyword for the link set (string)
+        """
+        if not self.__activating:
+            from .QtHelp.HelpTopicDialog import HelpTopicDialog
+            self.__activating = True
+            dlg = HelpTopicDialog(self, keyword, links)
+            if dlg.exec_() == QDialog.Accepted:
+                self.currentBrowser().setSource(dlg.link())
+            self.__activating = False
+    
     def __activateCurrentBrowser(self):
         """
         Private slot to activate the current browser.
         """
         self.currentBrowser().setFocus()
         
-    # TODO: QtHelp
-##    def __syncTOC(self):
-##        """
-##        Private slot to synchronize the TOC with the currently shown page.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            QApplication.setOverrideCursor(Qt.WaitCursor)
-##            url = self.currentBrowser().source()
-##            self.__showTocWindow()
-##            if not self.__tocWindow.syncToContent(url):
-##                self.statusBar().showMessage(
-##                    self.tr("Could not find an associated content."), 5000)
-##            QApplication.restoreOverrideCursor()
-##        
-##    def __showTocWindow(self):
-##        """
-##        Private method to show the table of contents window.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            self.__activateDock(self.__tocWindow)
-##        
+    def __syncTOC(self):
+        """
+        Private slot to synchronize the TOC with the currently shown page.
+        """
+        if WebBrowserWindow.UseQtHelp:
+            QApplication.setOverrideCursor(Qt.WaitCursor)
+            url = self.currentBrowser().source()
+            self.__showTocWindow()
+            if not self.__tocWindow.syncToContent(url):
+                self.statusBar().showMessage(
+                    self.tr("Could not find an associated content."), 5000)
+            QApplication.restoreOverrideCursor()
+        
+    def __showTocWindow(self):
+        """
+        Private method to show the table of contents window.
+        """
+        if WebBrowserWindow.useQtHelp:
+            self.__activateDock(self.__tocWindow)
+        
 ##    def __hideTocWindow(self):
 ##        """
 ##        Private method to hide the table of contents window.
@@ -3024,13 +3012,13 @@
 ##        if WebBrowserWindow.UseQtHelp:
 ##            self.__tocDock.hide()
 ##        
-##    def __showIndexWindow(self):
-##        """
-##        Private method to show the index window.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            self.__activateDock(self.__indexWindow)
-##        
+    def __showIndexWindow(self):
+        """
+        Private method to show the index window.
+        """
+        if WebBrowserWindow.useQtHelp:
+            self.__activateDock(self.__indexWindow)
+        
 ##    def __hideIndexWindow(self):
 ##        """
 ##        Private method to hide the index window.
@@ -3038,13 +3026,13 @@
 ##        if WebBrowserWindow.UseQtHelp:
 ##            self.__indexDock.hide()
 ##        
-##    def __showSearchWindow(self):
-##        """
-##        Private method to show the search window.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            self.__activateDock(self.__searchWindow)
-##        
+    def __showSearchWindow(self):
+        """
+        Private method to show the search window.
+        """
+        if WebBrowserWindow.useQtHelp:
+            self.__activateDock(self.__searchWindow)
+        
 ##    def __hideSearchWindow(self):
 ##        """
 ##        Private method to hide the search window.
@@ -3052,53 +3040,54 @@
 ##        if WebBrowserWindow.UseQtHelp:
 ##            self.__searchDock.hide()
 ##        
-##    def __activateDock(self, widget):
-##        """
-##        Private method to activate the dock widget of the given widget.
-##        
-##        @param widget reference to the widget to be activated (QWidget)
-##        """
-##        widget.parent().show()
-##        widget.parent().raise_()
-##        widget.setFocus()
-##        
-##    def __setupFilterCombo(self):
-##        """
-##        Private slot to setup the filter combo box.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            curFilter = self.filterCombo.currentText()
-##            if not curFilter:
-##                curFilter = self.__helpEngine.currentFilter()
-##            self.filterCombo.clear()
-##            self.filterCombo.addItems(self.__helpEngine.customFilters())
-##            idx = self.filterCombo.findText(curFilter)
-##            if idx < 0:
-##                idx = 0
-##            self.filterCombo.setCurrentIndex(idx)
-##        
-##    def __filterQtHelpDocumentation(self, customFilter):
-##        """
-##        Private slot to filter the QtHelp documentation.
-##        
-##        @param customFilter name of filter to be applied (string)
-##        """
-##        if self.__helpEngine:
-##            self.__helpEngine.setCurrentFilter(customFilter)
-##        
-##    def __manageQtHelpDocumentation(self):
-##        """
-##        Private slot to manage the QtHelp documentation database.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            from .QtHelpDocumentationDialog import QtHelpDocumentationDialog
-##            dlg = QtHelpDocumentationDialog(self.__helpEngine, self)
-##            dlg.exec_()
-##            if dlg.hasChanges():
-##                for i in sorted(dlg.getTabsToClose(), reverse=True):
-##                    self.__tabWidget.closeBrowserAt(i)
-##                self.__helpEngine.setupData()
-##        
+    def __activateDock(self, widget):
+        """
+        Private method to activate the dock widget of the given widget.
+        
+        @param widget reference to the widget to be activated (QWidget)
+        """
+        widget.parent().show()
+        widget.parent().raise_()
+        widget.setFocus()
+        
+    def __setupFilterCombo(self):
+        """
+        Private slot to setup the filter combo box.
+        """
+        if WebBrowserWindow.useQtHelp:
+            curFilter = self.filterCombo.currentText()
+            if not curFilter:
+                curFilter = self.__helpEngine.currentFilter()
+            self.filterCombo.clear()
+            self.filterCombo.addItems(self.__helpEngine.customFilters())
+            idx = self.filterCombo.findText(curFilter)
+            if idx < 0:
+                idx = 0
+            self.filterCombo.setCurrentIndex(idx)
+        
+    def __filterQtHelpDocumentation(self, customFilter):
+        """
+        Private slot to filter the QtHelp documentation.
+        
+        @param customFilter name of filter to be applied (string)
+        """
+        if self.__helpEngine:
+            self.__helpEngine.setCurrentFilter(customFilter)
+        
+    def __manageQtHelpDocumentation(self):
+        """
+        Private slot to manage the QtHelp documentation database.
+        """
+        if WebBrowserWindow.useQtHelp:
+            from .QtHelp.QtHelpDocumentationDialog import \
+                QtHelpDocumentationDialog
+            dlg = QtHelpDocumentationDialog(self.__helpEngine, self)
+            dlg.exec_()
+            if dlg.hasChanges():
+                for i in sorted(dlg.getTabsToClose(), reverse=True):
+                    self.__tabWidget.closeBrowserAt(i)
+                self.__helpEngine.setupData()
+        
     def getSourceFileList(self):
         """
         Public method to get a list of all opened source files.
@@ -3107,157 +3096,156 @@
         """
         return self.__tabWidget.getSourceFileList()
     
-    # TODO: QtHelp
-##    def __manageQtHelpFilters(self):
-##        """
-##        Private slot to manage the QtHelp filters.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            from .QtHelpFiltersDialog import QtHelpFiltersDialog
-##            dlg = QtHelpFiltersDialog(self.__helpEngine, self)
-##            dlg.exec_()
-##        
-##    def __indexingStarted(self):
-##        """
-##        Private slot to handle the start of the indexing process.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            self.__indexing = True
-##            if self.__indexingProgress is None:
-##                self.__indexingProgress = QWidget()
-##                layout = QHBoxLayout(self.__indexingProgress)
-##                layout.setContentsMargins(0, 0, 0, 0)
-##                sizePolicy = QSizePolicy(QSizePolicy.Preferred,
-##                                         QSizePolicy.Maximum)
-##                
-##                label = QLabel(self.tr("Updating search index"))
-##                label.setSizePolicy(sizePolicy)
-##                layout.addWidget(label)
-##                
-##                progressBar = QProgressBar()
-##                progressBar.setRange(0, 0)
-##                progressBar.setTextVisible(False)
-##                progressBar.setFixedHeight(16)
-##                progressBar.setSizePolicy(sizePolicy)
-##                layout.addWidget(progressBar)
-##                
-##                self.statusBar().insertPermanentWidget(
-##                    0, self.__indexingProgress)
-##        
-##    def __indexingFinished(self):
-##        """
-##        Private slot to handle the start of the indexing process.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            self.statusBar().removeWidget(self.__indexingProgress)
-##            self.__indexingProgress = None
-##            self.__indexing = False
-##            if self.__searchWord is not None:
-##                self.__searchForWord()
-##        
-##    def __searchForWord(self):
-##        """
-##        Private slot to search for a word.
-##        """
-##        if WebBrowserWindow.UseQtHelp and not self.__indexing and \
-##                self.__searchWord is not None:
-##            self.__searchDock.show()
-##            self.__searchDock.raise_()
-##            query = QHelpSearchQuery(QHelpSearchQuery.DEFAULT,
-##                                     [self.__searchWord])
-##            self.__searchEngine.search([query])
-##            self.__searchWord = None
-##        
-##    def search(self, word):
-##        """
-##        Public method to search for a word.
-##        
-##        @param word word to search for (string)
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            self.__searchWord = word
-##            self.__searchForWord()
-##        
-##    def __removeOldDocumentation(self):
-##        """
-##        Private slot to remove non-existing documentation from the help engine.
-##        """
-##        for namespace in self.__helpEngine.registeredDocumentations():
-##            docFile = self.__helpEngine.documentationFileName(namespace)
-##            if not os.path.exists(docFile):
-##                self.__helpEngine.unregisterDocumentation(namespace)
-##        
-##    def __lookForNewDocumentation(self):
-##        """
-##        Private slot to look for new documentation to be loaded into the
-##        help database.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            from .HelpDocsInstaller import HelpDocsInstaller
-##            self.__helpInstaller = HelpDocsInstaller(
-##                self.__helpEngine.collectionFile())
-##            self.__helpInstaller.errorMessage.connect(
-##                self.__showInstallationError)
-##            self.__helpInstaller.docsInstalled.connect(self.__docsInstalled)
-##            
-##            self.statusBar().showMessage(
-##                self.tr("Looking for Documentation..."))
-##            self.__helpInstaller.installDocs()
-##        
-##    def __showInstallationError(self, message):
-##        """
-##        Private slot to show installation errors.
-##        
-##        @param message message to be shown (string)
-##        """
-##        E5MessageBox.warning(
-##            self,
-##            self.tr("eric6 Web Browser"),
-##            message)
-##        
-##    def __docsInstalled(self, installed):
-##        """
-##        Private slot handling the end of documentation installation.
-##        
-##        @param installed flag indicating that documents were installed
-##            (boolean)
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            if installed:
-##                self.__helpEngine.setupData()
-##            self.statusBar().clearMessage()
-##        
-##    def __initHelpDb(self):
-##        """
-##        Private slot to initialize the documentation database.
-##        """
-##        if WebBrowserWindow.UseQtHelp:
-##            if not self.__helpEngine.setupData():
-##                return
-##            
-##            unfiltered = self.tr("Unfiltered")
-##            if unfiltered not in self.__helpEngine.customFilters():
-##                hc = QHelpEngineCore(self.__helpEngine.collectionFile())
-##                hc.setupData()
-##                hc.addCustomFilter(unfiltered, [])
-##                hc = None
-##                del hc
-##                
-##                self.__helpEngine.blockSignals(True)
-##                self.__helpEngine.setCurrentFilter(unfiltered)
-##                self.__helpEngine.blockSignals(False)
-##                self.__helpEngine.setupData()
-##        
-##    def __warning(self, msg):
-##        """
-##        Private slot handling warnings from the help engine.
-##        
-##        @param msg message sent by the help  engine (string)
-##        """
-##        E5MessageBox.warning(
-##            self,
-##            self.tr("Help Engine"), msg)
-##        
+    def __manageQtHelpFilters(self):
+        """
+        Private slot to manage the QtHelp filters.
+        """
+        if WebBrowserWindow.useQtHelp:
+            from .QtHelp.QtHelpFiltersDialog import QtHelpFiltersDialog
+            dlg = QtHelpFiltersDialog(self.__helpEngine, self)
+            dlg.exec_()
+        
+    def __indexingStarted(self):
+        """
+        Private slot to handle the start of the indexing process.
+        """
+        if WebBrowserWindow.useQtHelp:
+            self.__indexing = True
+            if self.__indexingProgress is None:
+                self.__indexingProgress = QWidget()
+                layout = QHBoxLayout(self.__indexingProgress)
+                layout.setContentsMargins(0, 0, 0, 0)
+                sizePolicy = QSizePolicy(QSizePolicy.Preferred,
+                                         QSizePolicy.Maximum)
+                
+                label = QLabel(self.tr("Updating search index"))
+                label.setSizePolicy(sizePolicy)
+                layout.addWidget(label)
+                
+                progressBar = QProgressBar()
+                progressBar.setRange(0, 0)
+                progressBar.setTextVisible(False)
+                progressBar.setFixedHeight(16)
+                progressBar.setSizePolicy(sizePolicy)
+                layout.addWidget(progressBar)
+                
+                self.statusBar().insertPermanentWidget(
+                    0, self.__indexingProgress)
+        
+    def __indexingFinished(self):
+        """
+        Private slot to handle the start of the indexing process.
+        """
+        if WebBrowserWindow.useQtHelp:
+            self.statusBar().removeWidget(self.__indexingProgress)
+            self.__indexingProgress = None
+            self.__indexing = False
+            if self.__searchWord is not None:
+                self.__searchForWord()
+        
+    def __searchForWord(self):
+        """
+        Private slot to search for a word.
+        """
+        if WebBrowserWindow.useQtHelp and not self.__indexing and \
+                self.__searchWord is not None:
+            self.__searchDock.show()
+            self.__searchDock.raise_()
+            query = QHelpSearchQuery(QHelpSearchQuery.DEFAULT,
+                                     [self.__searchWord])
+            self.__searchEngine.search([query])
+            self.__searchWord = None
+        
+    def search(self, word):
+        """
+        Public method to search for a word.
+        
+        @param word word to search for (string)
+        """
+        if WebBrowserWindow.useQtHelp:
+            self.__searchWord = word
+            self.__searchForWord()
+        
+    def __removeOldDocumentation(self):
+        """
+        Private slot to remove non-existing documentation from the help engine.
+        """
+        for namespace in self.__helpEngine.registeredDocumentations():
+            docFile = self.__helpEngine.documentationFileName(namespace)
+            if not os.path.exists(docFile):
+                self.__helpEngine.unregisterDocumentation(namespace)
+        
+    def __lookForNewDocumentation(self):
+        """
+        Private slot to look for new documentation to be loaded into the
+        help database.
+        """
+        if WebBrowserWindow.useQtHelp:
+            from .QtHelp.HelpDocsInstaller import HelpDocsInstaller
+            self.__helpInstaller = HelpDocsInstaller(
+                self.__helpEngine.collectionFile())
+            self.__helpInstaller.errorMessage.connect(
+                self.__showInstallationError)
+            self.__helpInstaller.docsInstalled.connect(self.__docsInstalled)
+            
+            self.statusBar().showMessage(
+                self.tr("Looking for Documentation..."))
+            self.__helpInstaller.installDocs()
+        
+    def __showInstallationError(self, message):
+        """
+        Private slot to show installation errors.
+        
+        @param message message to be shown (string)
+        """
+        E5MessageBox.warning(
+            self,
+            self.tr("eric6 Web Browser"),
+            message)
+        
+    def __docsInstalled(self, installed):
+        """
+        Private slot handling the end of documentation installation.
+        
+        @param installed flag indicating that documents were installed
+            (boolean)
+        """
+        if WebBrowserWindow.useQtHelp:
+            if installed:
+                self.__helpEngine.setupData()
+            self.statusBar().clearMessage()
+        
+    def __initHelpDb(self):
+        """
+        Private slot to initialize the documentation database.
+        """
+        if WebBrowserWindow.useQtHelp:
+            if not self.__helpEngine.setupData():
+                return
+            
+            unfiltered = self.tr("Unfiltered")
+            if unfiltered not in self.__helpEngine.customFilters():
+                hc = QHelpEngineCore(self.__helpEngine.collectionFile())
+                hc.setupData()
+                hc.addCustomFilter(unfiltered, [])
+                hc = None
+                del hc
+                
+                self.__helpEngine.blockSignals(True)
+                self.__helpEngine.setCurrentFilter(unfiltered)
+                self.__helpEngine.blockSignals(False)
+                self.__helpEngine.setupData()
+        
+    def __warning(self, msg):
+        """
+        Private slot handling warnings from the help engine.
+        
+        @param msg message sent by the help  engine (string)
+        """
+        E5MessageBox.warning(
+            self,
+            self.tr("Help Engine"), msg)
+        
     def __aboutToShowSettingsMenu(self):
         """
         Private slot to show the Settings menu.
--- a/eric6.e4p	Sat Mar 19 12:13:09 2016 +0100
+++ b/eric6.e4p	Sat Mar 19 16:05:11 2016 +0100
@@ -26,6 +26,54 @@
     <Source>DataViews/PyCoverageDialog.py</Source>
     <Source>DataViews/PyProfileDialog.py</Source>
     <Source>DataViews/__init__.py</Source>
+    <Source>DebugClients/Python/AsyncFile.py</Source>
+    <Source>DebugClients/Python/AsyncIO.py</Source>
+    <Source>DebugClients/Python/DCTestResult.py</Source>
+    <Source>DebugClients/Python/DebugBase.py</Source>
+    <Source>DebugClients/Python/DebugClient.py</Source>
+    <Source>DebugClients/Python/DebugClientBase.py</Source>
+    <Source>DebugClients/Python/DebugClientCapabilities.py</Source>
+    <Source>DebugClients/Python/DebugClientThreads.py</Source>
+    <Source>DebugClients/Python/DebugConfig.py</Source>
+    <Source>DebugClients/Python/DebugProtocol.py</Source>
+    <Source>DebugClients/Python/DebugThread.py</Source>
+    <Source>DebugClients/Python/FlexCompleter.py</Source>
+    <Source>DebugClients/Python/PyProfile.py</Source>
+    <Source>DebugClients/Python/__init__.py</Source>
+    <Source>DebugClients/Python/coverage/__init__.py</Source>
+    <Source>DebugClients/Python/coverage/__main__.py</Source>
+    <Source>DebugClients/Python/coverage/annotate.py</Source>
+    <Source>DebugClients/Python/coverage/backunittest.py</Source>
+    <Source>DebugClients/Python/coverage/backward.py</Source>
+    <Source>DebugClients/Python/coverage/bytecode.py</Source>
+    <Source>DebugClients/Python/coverage/cmdline.py</Source>
+    <Source>DebugClients/Python/coverage/collector.py</Source>
+    <Source>DebugClients/Python/coverage/config.py</Source>
+    <Source>DebugClients/Python/coverage/control.py</Source>
+    <Source>DebugClients/Python/coverage/data.py</Source>
+    <Source>DebugClients/Python/coverage/debug.py</Source>
+    <Source>DebugClients/Python/coverage/env.py</Source>
+    <Source>DebugClients/Python/coverage/execfile.py</Source>
+    <Source>DebugClients/Python/coverage/files.py</Source>
+    <Source>DebugClients/Python/coverage/html.py</Source>
+    <Source>DebugClients/Python/coverage/misc.py</Source>
+    <Source>DebugClients/Python/coverage/monkey.py</Source>
+    <Source>DebugClients/Python/coverage/parser.py</Source>
+    <Source>DebugClients/Python/coverage/phystokens.py</Source>
+    <Source>DebugClients/Python/coverage/pickle2json.py</Source>
+    <Source>DebugClients/Python/coverage/plugin.py</Source>
+    <Source>DebugClients/Python/coverage/plugin_support.py</Source>
+    <Source>DebugClients/Python/coverage/python.py</Source>
+    <Source>DebugClients/Python/coverage/pytracer.py</Source>
+    <Source>DebugClients/Python/coverage/report.py</Source>
+    <Source>DebugClients/Python/coverage/results.py</Source>
+    <Source>DebugClients/Python/coverage/summary.py</Source>
+    <Source>DebugClients/Python/coverage/templite.py</Source>
+    <Source>DebugClients/Python/coverage/test_helpers.py</Source>
+    <Source>DebugClients/Python/coverage/version.py</Source>
+    <Source>DebugClients/Python/coverage/xmlreport.py</Source>
+    <Source>DebugClients/Python/eric6dbgstub.py</Source>
+    <Source>DebugClients/Python/getpass.py</Source>
     <Source>DebugClients/Python3/AsyncFile.py</Source>
     <Source>DebugClients/Python3/AsyncIO.py</Source>
     <Source>DebugClients/Python3/DCTestResult.py</Source>
@@ -75,54 +123,6 @@
     <Source>DebugClients/Python3/coverage/xmlreport.py</Source>
     <Source>DebugClients/Python3/eric6dbgstub.py</Source>
     <Source>DebugClients/Python3/getpass.py</Source>
-    <Source>DebugClients/Python/AsyncFile.py</Source>
-    <Source>DebugClients/Python/AsyncIO.py</Source>
-    <Source>DebugClients/Python/DCTestResult.py</Source>
-    <Source>DebugClients/Python/DebugBase.py</Source>
-    <Source>DebugClients/Python/DebugClient.py</Source>
-    <Source>DebugClients/Python/DebugClientBase.py</Source>
-    <Source>DebugClients/Python/DebugClientCapabilities.py</Source>
-    <Source>DebugClients/Python/DebugClientThreads.py</Source>
-    <Source>DebugClients/Python/DebugConfig.py</Source>
-    <Source>DebugClients/Python/DebugProtocol.py</Source>
-    <Source>DebugClients/Python/DebugThread.py</Source>
-    <Source>DebugClients/Python/FlexCompleter.py</Source>
-    <Source>DebugClients/Python/PyProfile.py</Source>
-    <Source>DebugClients/Python/__init__.py</Source>
-    <Source>DebugClients/Python/coverage/__init__.py</Source>
-    <Source>DebugClients/Python/coverage/__main__.py</Source>
-    <Source>DebugClients/Python/coverage/annotate.py</Source>
-    <Source>DebugClients/Python/coverage/backunittest.py</Source>
-    <Source>DebugClients/Python/coverage/backward.py</Source>
-    <Source>DebugClients/Python/coverage/bytecode.py</Source>
-    <Source>DebugClients/Python/coverage/cmdline.py</Source>
-    <Source>DebugClients/Python/coverage/collector.py</Source>
-    <Source>DebugClients/Python/coverage/config.py</Source>
-    <Source>DebugClients/Python/coverage/control.py</Source>
-    <Source>DebugClients/Python/coverage/data.py</Source>
-    <Source>DebugClients/Python/coverage/debug.py</Source>
-    <Source>DebugClients/Python/coverage/env.py</Source>
-    <Source>DebugClients/Python/coverage/execfile.py</Source>
-    <Source>DebugClients/Python/coverage/files.py</Source>
-    <Source>DebugClients/Python/coverage/html.py</Source>
-    <Source>DebugClients/Python/coverage/misc.py</Source>
-    <Source>DebugClients/Python/coverage/monkey.py</Source>
-    <Source>DebugClients/Python/coverage/parser.py</Source>
-    <Source>DebugClients/Python/coverage/phystokens.py</Source>
-    <Source>DebugClients/Python/coverage/pickle2json.py</Source>
-    <Source>DebugClients/Python/coverage/plugin.py</Source>
-    <Source>DebugClients/Python/coverage/plugin_support.py</Source>
-    <Source>DebugClients/Python/coverage/python.py</Source>
-    <Source>DebugClients/Python/coverage/pytracer.py</Source>
-    <Source>DebugClients/Python/coverage/report.py</Source>
-    <Source>DebugClients/Python/coverage/results.py</Source>
-    <Source>DebugClients/Python/coverage/summary.py</Source>
-    <Source>DebugClients/Python/coverage/templite.py</Source>
-    <Source>DebugClients/Python/coverage/test_helpers.py</Source>
-    <Source>DebugClients/Python/coverage/version.py</Source>
-    <Source>DebugClients/Python/coverage/xmlreport.py</Source>
-    <Source>DebugClients/Python/eric6dbgstub.py</Source>
-    <Source>DebugClients/Python/getpass.py</Source>
     <Source>DebugClients/__init__.py</Source>
     <Source>Debugger/BreakPointModel.py</Source>
     <Source>Debugger/BreakPointViewer.py</Source>
@@ -1359,6 +1359,7 @@
     <Source>WebBrowser/Network/LoadRequest.py</Source>
     <Source>WebBrowser/Network/NetworkManager.py</Source>
     <Source>WebBrowser/Network/NetworkUrlInterceptor.py</Source>
+    <Source>WebBrowser/Network/QtHelpSchemeHandler.py</Source>
     <Source>WebBrowser/Network/SendRefererWhitelistDialog.py</Source>
     <Source>WebBrowser/Network/SslErrorExceptionsDialog.py</Source>
     <Source>WebBrowser/Network/UrlInterceptor.py</Source>
@@ -1385,6 +1386,14 @@
     <Source>WebBrowser/PersonalInformationManager/PersonalDataDialog.py</Source>
     <Source>WebBrowser/PersonalInformationManager/PersonalInformationManager.py</Source>
     <Source>WebBrowser/PersonalInformationManager/__init__.py</Source>
+    <Source>WebBrowser/QtHelp/HelpDocsInstaller.py</Source>
+    <Source>WebBrowser/QtHelp/HelpIndexWidget.py</Source>
+    <Source>WebBrowser/QtHelp/HelpSearchWidget.py</Source>
+    <Source>WebBrowser/QtHelp/HelpTocWidget.py</Source>
+    <Source>WebBrowser/QtHelp/HelpTopicDialog.py</Source>
+    <Source>WebBrowser/QtHelp/QtHelpDocumentationDialog.py</Source>
+    <Source>WebBrowser/QtHelp/QtHelpFiltersDialog.py</Source>
+    <Source>WebBrowser/QtHelp/__init__.py</Source>
     <Source>WebBrowser/SearchWidget.py</Source>
     <Source>WebBrowser/SiteInfo/SiteInfoDialog.py</Source>
     <Source>WebBrowser/SiteInfo/__init__.py</Source>
@@ -1874,6 +1883,9 @@
     <Form>WebBrowser/PageScreenDialog.ui</Form>
     <Form>WebBrowser/Passwords/PasswordsDialog.ui</Form>
     <Form>WebBrowser/PersonalInformationManager/PersonalDataDialog.ui</Form>
+    <Form>WebBrowser/QtHelp/HelpTopicDialog.ui</Form>
+    <Form>WebBrowser/QtHelp/QtHelpDocumentationDialog.ui</Form>
+    <Form>WebBrowser/QtHelp/QtHelpFiltersDialog.ui</Form>
     <Form>WebBrowser/SearchWidget.ui</Form>
     <Form>WebBrowser/SiteInfo/SiteInfoDialog.ui</Form>
     <Form>WebBrowser/Sync/SyncCheckPage.ui</Form>
@@ -1922,24 +1934,24 @@
     <Resource>Helpviewer/data/icons.qrc</Resource>
     <Resource>Helpviewer/data/javascript.qrc</Resource>
     <Resource>IconEditor/cursors/cursors.qrc</Resource>
-    <Resource>WebBrowser/data/qml.qrc</Resource>
     <Resource>WebBrowser/Bookmarks/DefaultBookmarks.qrc</Resource>
     <Resource>WebBrowser/OpenSearch/DefaultSearchEngines/DefaultSearchEngines.qrc</Resource>
     <Resource>WebBrowser/data/html.qrc</Resource>
     <Resource>WebBrowser/data/icons.qrc</Resource>
     <Resource>WebBrowser/data/javascript.qrc</Resource>
+    <Resource>WebBrowser/data/qml.qrc</Resource>
   </Resources>
   <Interfaces/>
   <Others>
     <Other>.hgignore</Other>
+    <Other>APIs/Python/zope-2.10.7.api</Other>
+    <Other>APIs/Python/zope-2.11.2.api</Other>
+    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/Python3/PyQt4.bas</Other>
     <Other>APIs/Python3/PyQt5.bas</Other>
     <Other>APIs/Python3/QScintilla2.bas</Other>
     <Other>APIs/Python3/eric6.api</Other>
     <Other>APIs/Python3/eric6.bas</Other>
-    <Other>APIs/Python/zope-2.10.7.api</Other>
-    <Other>APIs/Python/zope-2.11.2.api</Other>
-    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/QSS/qss.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.bas</Other>
@@ -1948,8 +1960,8 @@
     <Other>CSSs</Other>
     <Other>CodeTemplates</Other>
     <Other>DTDs</Other>
+    <Other>DebugClients/Python/coverage/doc</Other>
     <Other>DebugClients/Python3/coverage/doc</Other>
-    <Other>DebugClients/Python/coverage/doc</Other>
     <Other>DesignerTemplates</Other>
     <Other>Dictionaries</Other>
     <Other>Documentation/Help</Other>
--- a/eric6_browser.py	Sat Mar 19 12:13:09 2016 +0100
+++ b/eric6_browser.py	Sat Mar 19 16:05:11 2016 +0100
@@ -99,6 +99,8 @@
     
     searchWord = None
     private = False
+    qthelp = False
+    
     for arg in reversed(argv):
         if arg.startswith("--search="):
             searchWord = argv[1].split("=", 1)[1]
@@ -106,6 +108,9 @@
         elif arg == "--private":
             private = True
             argv.remove(arg)
+        elif arg == "--qthelp":
+            qthelp = True
+            argv.remove(arg)
         elif arg.startswith("--"):
             argv.remove(arg)
     
@@ -116,7 +121,7 @@
     
     browser = WebBrowserWindow(home, '.', None, 'web_browser',
                                searchWord=searchWord, private=private,
-                               settingsDir=SettingsDir)
+                               settingsDir=SettingsDir, qthelp=qthelp)
     return browser
 
 
@@ -128,6 +133,7 @@
         ("--config=configDir",
          "use the given directory as the one containing the config files"),
         ("--private", "start the browser in private browsing mode"),
+        ("--qthelp", "start the browser with support for QtHelp"),
         ("--search=word", "search for the given word"),
         ("--settings=settingsDir",
          "use the given directory to store the settings files"),

eric ide

mercurial