eric6/Helpviewer/HelpBrowserWV.py

changeset 7220
5cf645f6daab
parent 7218
eaf2cf171f3a
parent 7211
1c97f3142fa8
child 7221
0485ccdf7877
--- a/eric6/Helpviewer/HelpBrowserWV.py	Sat Sep 07 14:45:27 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2751 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2008 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-
-"""
-Module implementing the helpbrowser using QWebView.
-"""
-
-from __future__ import unicode_literals
-try:
-    str = unicode       # __IGNORE_EXCEPTION__
-except NameError:
-    pass
-
-import os
-
-from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QT_TRANSLATE_NOOP, \
-    QUrl, QBuffer, QIODevice, QFileInfo, Qt, QTimer, QEvent, \
-    QRect, QFile, QPoint, QByteArray
-from PyQt5.QtGui import QDesktopServices, QClipboard, QMouseEvent, QColor, \
-    QPalette
-from PyQt5.QtWidgets import qApp, QStyle, QMenu, QApplication, QInputDialog, \
-    QLineEdit, QLabel, QToolTip, QFrame, QDialog
-from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
-from PyQt5.QtWebKit import QWebSettings
-from PyQt5.QtWebKitWidgets import QWebView, QWebPage
-try:
-    from PyQt5.QtWebKit import QWebElement
-except ImportError:
-    pass
-from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
-try:
-    from PyQt5 import sip
-except ImportError:
-    import sip
-
-from E5Gui import E5MessageBox, E5FileDialog
-
-import Helpviewer
-
-import Preferences
-import UI.PixmapCache
-import Globals
-from Globals import qVersionTuple
-import Utilities
-
-try:
-    from PyQt5.QtNetwork import QSslCertificate
-    SSL_AVAILABLE = True
-except ImportError:
-    SSL_AVAILABLE = False
-
-###############################################################################
-
-
-class JavaScriptExternalObject(QObject):
-    """
-    Class implementing an external javascript object to add search providers.
-    """
-    def __init__(self, mw, parent=None):
-        """
-        Constructor
-        
-        @param mw reference to the main window 8HelpWindow)
-        @param parent reference to the parent object (QObject)
-        """
-        super(JavaScriptExternalObject, self).__init__(parent)
-        
-        self.__mw = mw
-    
-    @pyqtSlot(str)
-    def AddSearchProvider(self, url):
-        """
-        Public slot to add a search provider.
-        
-        @param url url of the XML file defining the search provider (string)
-        """
-        self.__mw.openSearchManager().addEngine(QUrl(url))
-
-
-class LinkedResource(object):
-    """
-    Class defining a data structure for linked resources.
-    """
-    def __init__(self):
-        """
-        Constructor
-        """
-        self.rel = ""
-        self.type_ = ""
-        self.href = ""
-        self.title = ""
-
-###############################################################################
-
-
-class JavaScriptEricObject(QObject):
-    """
-    Class implementing an external javascript object to search via the
-    startpage.
-    """
-    # these must be in line with the strings used by the javascript part of
-    # the start page
-    translations = [
-        QT_TRANSLATE_NOOP("JavaScriptEricObject",
-                          "Welcome to eric6 Web Browser!"),
-        QT_TRANSLATE_NOOP("JavaScriptEricObject", "eric6 Web Browser"),
-        QT_TRANSLATE_NOOP("JavaScriptEricObject", "Search!"),
-        QT_TRANSLATE_NOOP("JavaScriptEricObject", "About eric6"),
-    ]
-    
-    def __init__(self, mw, parent=None):
-        """
-        Constructor
-        
-        @param mw reference to the main window 8HelpWindow)
-        @param parent reference to the parent object (QObject)
-        """
-        super(JavaScriptEricObject, self).__init__(parent)
-        
-        self.__mw = mw
-    
-    @pyqtSlot(str, result=str)
-    def translate(self, trans):
-        """
-        Public method to translate the given string.
-        
-        @param trans string to be translated (string)
-        @return translation (string)
-        """
-        if trans == "QT_LAYOUT_DIRECTION":
-            # special handling to detect layout direction
-            if qApp.isLeftToRight():
-                return "LTR"
-            else:
-                return "RTL"
-        
-        return self.tr(trans)
-    
-    @pyqtSlot(result=str)
-    def providerString(self):
-        """
-        Public method to get a string for the search provider.
-        
-        @return string for the search provider (string)
-        """
-        return self.tr("Search results provided by {0}")\
-            .format(self.__mw.openSearchManager().currentEngineName())
-    
-    @pyqtSlot(str, result=str)
-    def searchUrl(self, searchStr):
-        """
-        Public method to get the search URL for the given search term.
-        
-        @param searchStr search term (string)
-        @return search URL (string)
-        """
-        return bytes(
-            self.__mw.openSearchManager().currentEngine()
-            .searchUrl(searchStr).toEncoded()).decode()
-
-###############################################################################
-
-
-class HelpWebPage(QWebPage):
-    """
-    Class implementing an enhanced web page.
-    """
-    _webPluginFactory = None
-    
-    def __init__(self, parent=None):
-        """
-        Constructor
-        
-        @param parent parent widget of this window (QWidget)
-        """
-        super(HelpWebPage, self).__init__(parent)
-        
-        self.setPluginFactory(self.webPluginFactory())
-        
-        self.__lastRequest = None
-        self.__lastRequestType = QWebPage.NavigationTypeOther
-        
-        import Helpviewer.HelpWindow
-        from .Network.NetworkAccessManagerProxy import \
-            NetworkAccessManagerProxy
-        self.__proxy = NetworkAccessManagerProxy(self)
-        self.__proxy.setWebPage(self)
-        self.__proxy.setPrimaryNetworkAccessManager(
-            Helpviewer.HelpWindow.HelpWindow.networkAccessManager())
-        self.setNetworkAccessManager(self.__proxy)
-        
-        self.__sslConfiguration = None
-        self.__proxy.finished.connect(self.__managerFinished)
-        
-        self.__adBlockedEntries = []
-        self.loadStarted.connect(self.__loadStarted)
-        
-        self.saveFrameStateRequested.connect(
-            self.__saveFrameStateRequested)
-        self.restoreFrameStateRequested.connect(
-            self.__restoreFrameStateRequested)
-    
-    def acceptNavigationRequest(self, frame, request, type_):
-        """
-        Public method to determine, if a request may be accepted.
-        
-        @param frame reference to the frame sending the request (QWebFrame)
-        @param request reference to the request object (QNetworkRequest)
-        @param type_ type of the navigation request (QWebPage.NavigationType)
-        @return flag indicating acceptance (boolean)
-        """
-        self.__lastRequest = request
-        if self.__lastRequest.url() != request.url() or \
-           type_ != QWebPage.NavigationTypeOther:
-            self.__lastRequestType = type_
-        
-        scheme = request.url().scheme()
-        if scheme == "mailto":
-            QDesktopServices.openUrl(request.url())
-            return False
-        
-        if type_ == QWebPage.NavigationTypeFormResubmitted:
-            res = E5MessageBox.yesNo(
-                self.view(),
-                self.tr("Resending POST request"),
-                self.tr(
-                    """In order to display the site, the request along with"""
-                    """ all the data must be sent once again, which may lead"""
-                    """ to some unexpected behaviour of the site e.g. the"""
-                    """ same action might be performed once again. Do you"""
-                    """ want to continue anyway?"""),
-                icon=E5MessageBox.Warning)
-            if not res:
-                return False
-        
-        return QWebPage.acceptNavigationRequest(self, frame, request, type_)
-    
-    def populateNetworkRequest(self, request):
-        """
-        Public method to add data to a network request.
-        
-        @param request reference to the network request object
-            (QNetworkRequest)
-        """
-        try:
-            request.setAttribute(QNetworkRequest.User + 100, self)
-            if self.__lastRequest.url() == request.url():
-                request.setAttribute(QNetworkRequest.User + 101,
-                                     self.__lastRequestType)
-                if self.__lastRequestType == \
-                        QWebPage.NavigationTypeLinkClicked:
-                    request.setRawHeader(b"X-Eric6-UserLoadAction",
-                                         QByteArray(b"1"))
-        except TypeError:
-            pass
-    
-    def pageAttributeId(self):
-        """
-        Public method to get the attribute id of the page attribute.
-        
-        @return attribute id of the page attribute (integer)
-        """
-        return QNetworkRequest.User + 100
-    
-    def supportsExtension(self, extension):
-        """
-        Public method to check the support for an extension.
-        
-        @param extension extension to test for (QWebPage.Extension)
-        @return flag indicating the support of extension (boolean)
-        """
-        try:
-            if extension in [QWebPage.ErrorPageExtension,
-                             QWebPage.ChooseMultipleFilesExtension]:
-                return True
-        except AttributeError:
-            pass
-        
-        return QWebPage.supportsExtension(self, extension)
-    
-    def extension(self, extension, option, output):
-        """
-        Public method to implement a specific extension.
-        
-        @param extension extension to be executed (QWebPage.Extension)
-        @param option provides input to the extension
-            (QWebPage.ExtensionOption)
-        @param output stores the output results (QWebPage.ExtensionReturn)
-        @return flag indicating a successful call of the extension (boolean)
-        """
-        if extension == QWebPage.ChooseMultipleFilesExtension:
-            info = sip.cast(option,
-                            QWebPage.ChooseMultipleFilesExtensionOption)
-            files = sip.cast(output,
-                             QWebPage.ChooseMultipleFilesExtensionReturn)
-            if info is None or files is None:
-                return super(HelpWebPage, self).extension(
-                    extension, option, output)
-            
-            suggestedFileName = ""
-            if info.suggestedFileNames:
-                suggestedFileName = info.suggestedFileNames[0]
-            
-            files.fileNames = E5FileDialog.getOpenFileNames(
-                None,
-                self.tr("Select files to upload..."),
-                suggestedFileName)
-            return True
-        
-        if extension == QWebPage.ErrorPageExtension:
-            info = sip.cast(option, QWebPage.ErrorPageExtensionOption)
-            
-            errorPage = sip.cast(output, QWebPage.ErrorPageExtensionReturn)
-            urlString = bytes(info.url.toEncoded()).decode()
-            errorPage.baseUrl = info.url
-            if info.domain == QWebPage.QtNetwork and \
-               info.error == QNetworkReply.ProtocolUnknownError:
-                url = QUrl(info.url)
-                res = E5MessageBox.yesNo(
-                    None,
-                    self.tr("Protocol Error"),
-                    self.tr("""Open external application for {0}-link?\n"""
-                            """URL: {1}""").format(
-                        url.scheme(), url.toString(
-                            QUrl.PrettyDecoded | QUrl.RemovePassword)),
-                    yesDefault=True)
-                
-                if res:
-                    QDesktopServices.openUrl(url)
-                return True
-            elif info.domain == QWebPage.QtNetwork and \
-                info.error == QNetworkReply.ContentAccessDenied and \
-                    info.errorString.startswith("AdBlockRule:"):
-                if info.frame != info.frame.page().mainFrame():
-                    # content in <iframe>
-                    docElement = info.frame.page().mainFrame()\
-                        .documentElement()
-                    for element in docElement.findAll("iframe"):
-                        src = element.attribute("src")
-                        if src in info.url.toString():
-                            element.setAttribute("style", "display:none;")
-                    return False
-                else:
-                    # the whole page is blocked
-                    rule = info.errorString.replace("AdBlockRule:", "")
-                    title = self.tr("Content blocked by AdBlock Plus")
-                    message = self.tr(
-                        "Blocked by rule: <i>{0}</i>").format(rule)
-                    
-                    htmlFile = QFile(":/html/adblockPage.html")
-                    htmlFile.open(QFile.ReadOnly)
-                    html = htmlFile.readAll()
-                    html = html.replace(
-                        "@FAVICON@", "qrc:icons/adBlockPlus16.png")
-                    html = html.replace(
-                        "@IMAGE@", "qrc:icons/adBlockPlus64.png")
-                    html = html.replace("@TITLE@", title.encode("utf8"))
-                    html = html.replace("@MESSAGE@", message.encode("utf8"))
-                    errorPage.content = html
-                    return True
-            
-            if info.domain == QWebPage.QtNetwork and \
-               info.error == QNetworkReply.OperationCanceledError and \
-               info.errorString == "eric6:No Error":
-                return False
-            
-            if info.domain == QWebPage.WebKit and info.error == 203:
-                # "Loading is handled by the media engine"
-                return False
-            
-            title = self.tr("Error loading page: {0}").format(urlString)
-            htmlFile = QFile(":/html/notFoundPage.html")
-            htmlFile.open(QFile.ReadOnly)
-            html = htmlFile.readAll()
-            pixmap = qApp.style()\
-                .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48)
-            imageBuffer = QBuffer()
-            imageBuffer.open(QIODevice.ReadWrite)
-            if pixmap.save(imageBuffer, "PNG"):
-                html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64())
-            pixmap = qApp.style()\
-                .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16)
-            imageBuffer = QBuffer()
-            imageBuffer.open(QIODevice.ReadWrite)
-            if pixmap.save(imageBuffer, "PNG"):
-                html = html.replace(
-                    "@FAVICON@", imageBuffer.buffer().toBase64())
-            html = html.replace("@TITLE@", title.encode("utf8"))
-            html = html.replace("@H1@", info.errorString.encode("utf8"))
-            html = html.replace(
-                "@H2@", self.tr("When connecting to: {0}.")
-                .format(urlString).encode("utf8"))
-            html = html.replace(
-                "@LI-1@",
-                self.tr("Check the address for errors such as "
-                        "<b>ww</b>.example.org instead of "
-                        "<b>www</b>.example.org").encode("utf8"))
-            html = html.replace(
-                "@LI-2@",
-                self.tr(
-                    "If the address is correct, try checking the network "
-                    "connection.").encode("utf8"))
-            html = html.replace(
-                "@LI-3@",
-                self.tr(
-                    "If your computer or network is protected by a firewall "
-                    "or proxy, make sure that the browser is permitted to "
-                    "access the network.").encode("utf8"))
-            html = html.replace(
-                "@LI-4@",
-                self.tr("If your cache policy is set to offline browsing,"
-                        "only pages in the local cache are available.")
-                .encode("utf8"))
-            html = html.replace(
-                "@BUTTON@", self.tr("Try Again").encode("utf8"))
-            errorPage.content = html
-            return True
-        
-        return QWebPage.extension(self, extension, option, output)
-    
-    def __loadStarted(self):
-        """
-        Private method to handle the loadStarted signal.
-        """
-        self.__adBlockedEntries = []
-    
-    def addAdBlockRule(self, rule, url):
-        """
-        Public slot to add an AdBlock rule to the page.
-        
-        @param rule AdBlock rule to add (AdBlockRule)
-        @param url URL that matched the rule (QUrl)
-        """
-        from .AdBlock.AdBlockPage import AdBlockedPageEntry
-        entry = AdBlockedPageEntry(rule, url)
-        if entry not in self.__adBlockedEntries:
-            self.__adBlockedEntries.append(entry)
-    
-    def getAdBlockedPageEntries(self):
-        """
-        Public method to get the list of AdBlock page entries.
-        
-        @return list of AdBlock page entries (list of AdBlockedPageEntry)
-        """
-        return self.__adBlockedEntries
-    
-    def url(self):
-        """
-        Public method to get the URL of the page.
-        
-        @return URL of the page (QUrl)
-        """
-        return self.mainFrame().url()
-    
-    def userAgent(self, resolveEmpty=False):
-        """
-        Public method to get the global user agent setting.
-        
-        @param resolveEmpty flag indicating to resolve an empty
-            user agent (boolean)
-        @return user agent string (string)
-        """
-        agent = Preferences.getHelp("UserAgent")
-        if agent == "" and resolveEmpty:
-            agent = self.userAgentForUrl(QUrl())
-        return agent
-    
-    def setUserAgent(self, agent):
-        """
-        Public method to set the global user agent string.
-        
-        @param agent new current user agent string (string)
-        """
-        Preferences.setHelp("UserAgent", agent)
-    
-    def userAgentForUrl(self, url):
-        """
-        Public method to determine the user agent for the given URL.
-        
-        @param url URL to determine user agent for (QUrl)
-        @return user agent string (string)
-        """
-        import Helpviewer.HelpWindow
-        agent = Helpviewer.HelpWindow.HelpWindow.userAgentsManager()\
-            .userAgentForUrl(url)
-        if agent == "":
-            # no agent string specified for the given host -> use global one
-            agent = Preferences.getHelp("UserAgent")
-            if agent == "":
-                # no global agent string specified -> use default one
-                agent = QWebPage.userAgentForUrl(self, url)
-        return agent
-    
-    def __managerFinished(self, reply):
-        """
-        Private slot to handle a finished reply.
-        
-        This slot is used to get SSL related information for a reply.
-        
-        @param reply reference to the finished reply (QNetworkReply)
-        """
-        try:
-            frame = reply.request().originatingObject()
-        except AttributeError:
-            frame = None
-        
-        mainFrameRequest = frame == self.mainFrame()
-        
-        if mainFrameRequest and \
-           self.__sslConfiguration is not None and \
-           reply.url() == self.mainFrame().url():
-            self.__sslConfiguration = None
-        
-        if reply.error() == QNetworkReply.NoError and \
-           mainFrameRequest and \
-           self.__sslConfiguration is None and \
-           reply.url().scheme().lower() == "https" and \
-           reply.url() == self.mainFrame().url():
-            self.__sslConfiguration = reply.sslConfiguration()
-            self.__sslConfiguration.url = QUrl(reply.url())
-        
-        if reply.error() == QNetworkReply.NoError and \
-           mainFrameRequest and \
-           reply.url() == self.mainFrame().url():
-            modified = reply.header(QNetworkRequest.LastModifiedHeader)
-            if modified and modified.isValid():
-                import Helpviewer.HelpWindow
-                manager = Helpviewer.HelpWindow.HelpWindow.bookmarksManager()
-                from .Bookmarks.BookmarkNode import BookmarkNode
-                for bookmark in manager.bookmarksForUrl(reply.url()):
-                    manager.setTimestamp(bookmark, BookmarkNode.TsModified,
-                                         modified)
-    
-    def getSslCertificate(self):
-        """
-        Public method to get a reference to the SSL certificate.
-        
-        @return amended SSL certificate (QSslCertificate)
-        """
-        if self.__sslConfiguration is None:
-            return None
-        
-        sslInfo = self.__sslConfiguration.peerCertificate()
-        sslInfo.url = QUrl(self.__sslConfiguration.url)
-        return sslInfo
-    
-    def getSslCertificateChain(self):
-        """
-        Public method to get a reference to the SSL certificate chain.
-        
-        @return SSL certificate chain (list of QSslCertificate)
-        """
-        if self.__sslConfiguration is None:
-            return []
-        
-        chain = self.__sslConfiguration.peerCertificateChain()
-        return chain
-    
-    def getSslConfiguration(self):
-        """
-        Public method to return a reference to the current SSL configuration.
-        
-        @return reference to the SSL configuration in use (QSslConfiguration)
-        """
-        return self.__sslConfiguration
-    
-    def showSslInfo(self, pos):
-        """
-        Public slot to show some SSL information for the loaded page.
-        
-        @param pos position to show the info at (QPoint)
-        """
-        if SSL_AVAILABLE and self.__sslConfiguration is not None:
-            from E5Network.E5SslInfoWidget import E5SslInfoWidget
-            widget = E5SslInfoWidget(
-                self.mainFrame().url(), self.__sslConfiguration, self.view())
-            widget.showAt(pos)
-        else:
-            E5MessageBox.warning(
-                self.view(),
-                self.tr("SSL Info"),
-                self.tr("""This site does not contain SSL information."""))
-    
-    def hasValidSslInfo(self):
-        """
-        Public method to check, if the page has a valid SSL certificate.
-        
-        @return flag indicating a valid SSL certificate (boolean)
-        """
-        if self.__sslConfiguration is None:
-            return False
-        
-        certList = self.__sslConfiguration.peerCertificateChain()
-        if not certList:
-            return False
-        
-        certificateDict = Globals.toDict(
-            Preferences.Prefs.settings.value("Ssl/CaCertificatesDict"))
-        for server in certificateDict:
-            localCAList = QSslCertificate.fromData(certificateDict[server])
-            for cert in certList:
-                if cert in localCAList:
-                    return True
-        
-        if qVersionTuple() >= (5, 0, 0):
-            for cert in certList:
-                if cert.isBlacklisted():
-                    return False
-        else:
-            for cert in certList:
-                if not cert.isValid():
-                    return False
-        
-        return True
-    
-    @classmethod
-    def webPluginFactory(cls):
-        """
-        Class method to get a reference to the web plug-in factory
-        instance.
-        
-        @return reference to the web plug-in factory instance (WebPluginFactory
-        """
-        if cls._webPluginFactory is None:
-            from .WebPlugins.WebPluginFactory import WebPluginFactory
-            cls._webPluginFactory = WebPluginFactory()
-        
-        return cls._webPluginFactory
-    
-    def event(self, evt):
-        """
-        Public method implementing the event handler.
-        
-        @param evt reference to the event (QEvent)
-        @return flag indicating that the event was handled (boolean)
-        """
-        if evt.type() == QEvent.Leave:
-            # Fake a mouse move event just outside of the widget to trigger
-            # the WebKit event handler's mouseMoved function. This implements
-            # the interesting mouse-out behavior like invalidating scrollbars.
-            fakeEvent = QMouseEvent(QEvent.MouseMove, QPoint(0, -1),
-                                    Qt.NoButton, Qt.NoButton, Qt.NoModifier)
-            return super(HelpWebPage, self).event(fakeEvent)
-        
-        return super(HelpWebPage, self).event(evt)
-    
-    def __saveFrameStateRequested(self, frame, itm):
-        """
-        Private slot to save the page state (i.e. zoom level and scroll
-        position).
-        
-        Note: Code is based on qutebrowser.
-        
-        @param frame frame to be saved
-        @type QWebFrame
-        @param itm web history item to be saved
-        @type QWebHistoryItem
-        """
-        try:
-            if frame != self.mainFrame():
-                return
-        except RuntimeError:
-            # With Qt 5.2.1 (Ubuntu Trusty) we get this when closing a tab:
-            #     RuntimeError: wrapped C/C++ object of type BrowserPage has
-            #     been deleted
-            # Since the information here isn't that important for closing web
-            # views anyways, we ignore this error.
-            return
-        data = {
-            'zoom': frame.zoomFactor(),
-            'scrollPos': frame.scrollPosition(),
-        }
-        itm.setUserData(data)
-    
-    def __restoreFrameStateRequested(self, frame):
-        """
-        Private slot to restore scroll position and zoom level from
-        history.
-        
-        Note: Code is based on qutebrowser.
-        
-        @param frame frame to be restored
-        @type QWebFrame
-        """
-        if frame != self.mainFrame():
-            return
-        
-        data = self.history().currentItem().userData()
-        if data is None:
-            return
-        
-        if 'zoom' in data:
-            frame.page().view().setZoomValue(int(data['zoom'] * 100),
-                                             saveValue=False)
-        
-        if 'scrollPos' in data and frame.scrollPosition() == QPoint(0, 0):
-            frame.setScrollPosition(data['scrollPos'])
-
-###############################################################################
-
-
-class HelpBrowser(QWebView):
-    """
-    Class implementing the helpbrowser widget.
-    
-    This is a subclass of the Qt QWebView to implement an
-    interface compatible with the QTextBrowser based variant.
-    
-    @signal sourceChanged(QUrl) emitted after the current URL has changed
-    @signal forwardAvailable(bool) emitted after the current URL has changed
-    @signal backwardAvailable(bool) emitted after the current URL has changed
-    @signal highlighted(str) emitted, when the mouse hovers over a link
-    @signal search(QUrl) emitted, when a search is requested
-    @signal zoomValueChanged(int) emitted to signal a change of the zoom value
-    """
-    sourceChanged = pyqtSignal(QUrl)
-    forwardAvailable = pyqtSignal(bool)
-    backwardAvailable = pyqtSignal(bool)
-    highlighted = pyqtSignal(str)
-    search = pyqtSignal(QUrl)
-    zoomValueChanged = pyqtSignal(int)
-    
-    ZoomLevels = [
-        30, 50, 67, 80, 90,
-        100,
-        110, 120, 133, 150, 170, 200, 240, 300,
-    ]
-    ZoomLevelDefault = 100
-    
-    def __init__(self, mainWindow, parent=None, name=""):
-        """
-        Constructor
-        
-        @param mainWindow reference to the main window (HelpWindow)
-        @param parent parent widget of this window (QWidget)
-        @param name name of this window (string)
-        """
-        super(HelpBrowser, self).__init__(parent)
-        self.setObjectName(name)
-        self.setWhatsThis(self.tr(
-            """<b>Help Window</b>"""
-            """<p>This window displays the selected help information.</p>"""
-        ))
-        
-        import Helpviewer.HelpWindow
-        self.__speedDial = Helpviewer.HelpWindow.HelpWindow.speedDial()
-        
-        self.__page = HelpWebPage(self)
-        self.setPage(self.__page)
-        
-        self.mw = mainWindow
-        self.ctrlPressed = False
-        self.__isLoading = False
-        self.__progress = 0
-        
-        self.__currentZoom = 100
-        self.__zoomLevels = HelpBrowser.ZoomLevels[:]
-        
-        self.__javaScriptBinding = None
-        self.__javaScriptEricObject = None
-        
-        self.mw.zoomTextOnlyChanged.connect(self.__applyZoom)
-        
-        self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
-        self.linkClicked.connect(self.setSource)
-        
-        self.urlChanged.connect(self.__urlChanged)
-        self.statusBarMessage.connect(self.__statusBarMessage)
-        self.page().linkHovered.connect(self.__linkHovered)
-        
-        self.loadStarted.connect(self.__loadStarted)
-        self.loadProgress.connect(self.__loadProgress)
-        self.loadFinished.connect(self.__loadFinished)
-        
-        self.page().setForwardUnsupportedContent(True)
-        self.page().unsupportedContent.connect(self.__unsupportedContent)
-        
-        self.page().featurePermissionRequested.connect(
-            self.__featurePermissionRequested)
-        
-        self.page().downloadRequested.connect(self.__downloadRequested)
-        self.page().frameCreated.connect(self.__addExternalBinding)
-        self.__addExternalBinding(self.page().mainFrame())
-        
-        self.page().databaseQuotaExceeded.connect(self.__databaseQuotaExceeded)
-        
-        self.mw.openSearchManager().currentEngineChanged.connect(
-            self.__currentEngineChanged)
-        
-        self.setAcceptDrops(True)
-        
-        self.__enableAccessKeys = Preferences.getHelp("AccessKeysEnabled")
-        self.__accessKeysPressed = False
-        self.__accessKeyLabels = []
-        self.__accessKeyNodes = {}
-        
-        self.page().loadStarted.connect(self.__hideAccessKeys)
-        self.page().scrollRequested.connect(self.__hideAccessKeys)
-        
-        self.__rss = []
-        
-        self.__clickedFrame = None
-        
-        self.mw.personalInformationManager().connectPage(self.page())
-        self.mw.greaseMonkeyManager().connectPage(self.page())
-        
-        self.__inspector = None
-        
-        self.grabGesture(Qt.PinchGesture)
-    
-    def __addExternalBinding(self, frame=None):
-        """
-        Private slot to add javascript bindings for adding search providers.
-        
-        @param frame reference to the web frame
-        @type QWebFrame
-        """
-        self.page().settings().setAttribute(QWebSettings.JavascriptEnabled,
-                                            True)
-        if self.__javaScriptBinding is None:
-            self.__javaScriptBinding = JavaScriptExternalObject(self.mw, self)
-        
-        if frame is None:
-            frame = self.sender()
-            # called from QWebFrame.javaScriptWindowObjectCleared
-            if isinstance(frame, HelpWebPage):
-                frame = frame.mainFrame()
-            if frame.url().scheme() == "eric" and frame.url().path() == "home":
-                if self.__javaScriptEricObject is None:
-                    self.__javaScriptEricObject = JavaScriptEricObject(
-                        self.mw, self)
-                frame.addToJavaScriptWindowObject(
-                    "eric", self.__javaScriptEricObject)
-            elif frame.url().scheme() == "eric" and \
-                    frame.url().path() == "speeddial":
-                frame.addToJavaScriptWindowObject(
-                    "speeddial", self.__speedDial)
-                self.__speedDial.addWebFrame(frame)
-        else:
-            # called from QWebPage.frameCreated
-            frame.javaScriptWindowObjectCleared.connect(
-                self.__addExternalBinding)
-        frame.addToJavaScriptWindowObject("external", self.__javaScriptBinding)
-    
-    def linkedResources(self, relation=""):
-        """
-        Public method to extract linked resources.
-        
-        @param relation relation to extract (string)
-        @return list of linked resources (list of LinkedResource)
-        """
-        resources = []
-        
-        baseUrl = self.page().mainFrame().baseUrl()
-        
-        linkElements = self.page().mainFrame().findAllElements(
-            "html > head > link")
-        
-        for linkElement in linkElements.toList():
-            rel = linkElement.attribute("rel")
-            href = linkElement.attribute("href")
-            type_ = linkElement.attribute("type")
-            title = linkElement.attribute("title")
-            
-            if href == "" or type_ == "":
-                continue
-            if relation and rel != relation:
-                continue
-            
-            resource = LinkedResource()
-            resource.rel = rel
-            resource.type_ = type_
-            resource.href = baseUrl.resolved(
-                QUrl.fromEncoded(href.encode("utf-8")))
-            resource.title = title
-            
-            resources.append(resource)
-        
-        return resources
-    
-    def __currentEngineChanged(self):
-        """
-        Private slot to track a change of the current search engine.
-        """
-        if self.url().toString() == "eric:home":
-            self.reload()
-    
-    def setSource(self, name, requestData=None):
-        """
-        Public method used to set the source to be displayed.
-        
-        @param name filename to be shown (QUrl)
-        @param requestData tuple containing the request data (QNetworkRequest,
-            QNetworkAccessManager.Operation, QByteArray)
-        """
-        if (name is None or not name.isValid()) and requestData is None:
-            return
-        
-        if name is None and requestData is not None:
-            name = requestData[0].url()
-        
-        if self.ctrlPressed:
-            # open in a new window
-            self.mw.newTab(name)
-            self.ctrlPressed = False
-            return
-        
-        if not name.scheme():
-            if not os.path.exists(name.toString()):
-                name.setScheme(Preferences.getWebBrowser("DefaultScheme"))
-            else:
-                if Utilities.isWindowsPlatform():
-                    name.setUrl("file:///" + Utilities.fromNativeSeparators(
-                        name.toString()))
-                else:
-                    name.setUrl("file://" + name.toString())
-        
-        if len(name.scheme()) == 1 or \
-           name.scheme() == "file":
-            # name is a local file
-            if name.scheme() and len(name.scheme()) == 1:
-                # it is a local path on win os
-                name = QUrl.fromLocalFile(name.toString())
-            
-            if not QFileInfo(name.toLocalFile()).exists():
-                E5MessageBox.critical(
-                    self,
-                    self.tr("eric6 Web Browser"),
-                    self.tr(
-                        """<p>The file <b>{0}</b> does not exist.</p>""")
-                    .format(name.toLocalFile()))
-                return
-
-            if name.toLocalFile().endswith(".pdf") or \
-               name.toLocalFile().endswith(".PDF") or \
-               name.toLocalFile().endswith(".chm") or \
-               name.toLocalFile().endswith(".CHM"):
-                started = QDesktopServices.openUrl(name)
-                if not started:
-                    E5MessageBox.critical(
-                        self,
-                        self.tr("eric6 Web Browser"),
-                        self.tr(
-                            """<p>Could not start a viewer"""
-                            """ for file <b>{0}</b>.</p>""")
-                        .format(name.path()))
-                return
-        elif name.scheme() in ["mailto"]:
-            started = QDesktopServices.openUrl(name)
-            if not started:
-                E5MessageBox.critical(
-                    self,
-                    self.tr("eric6 Web Browser"),
-                    self.tr(
-                        """<p>Could not start an application"""
-                        """ for URL <b>{0}</b>.</p>""")
-                    .format(name.toString()))
-            return
-        elif name.scheme() == "javascript":
-            scriptSource = QUrl.fromPercentEncoding(name.toString(
-                QUrl.FormattingOptions(QUrl.TolerantMode | QUrl.RemoveScheme)))
-            self.page().mainFrame().evaluateJavaScript(scriptSource)
-            return
-        else:
-            if name.toString().endswith(".pdf") or \
-               name.toString().endswith(".PDF") or \
-               name.toString().endswith(".chm") or \
-               name.toString().endswith(".CHM"):
-                started = QDesktopServices.openUrl(name)
-                if not started:
-                    E5MessageBox.critical(
-                        self,
-                        self.tr("eric6 Web Browser"),
-                        self.tr(
-                            """<p>Could not start a viewer"""
-                            """ for file <b>{0}</b>.</p>""")
-                        .format(name.path()))
-                return
-        
-        if requestData is not None:
-            self.load(*requestData)
-        else:
-            self.load(name)
-
-    def source(self):
-        """
-        Public method to return the URL of the loaded page.
-        
-        @return URL loaded in the help browser (QUrl)
-        """
-        return self.url()
-    
-    def documentTitle(self):
-        """
-        Public method to return the title of the loaded page.
-        
-        @return title (string)
-        """
-        return self.title()
-    
-    def backward(self):
-        """
-        Public slot to move backwards in history.
-        """
-        self.triggerPageAction(QWebPage.Back)
-        self.__urlChanged(self.history().currentItem().url())
-    
-    def forward(self):
-        """
-        Public slot to move forward in history.
-        """
-        self.triggerPageAction(QWebPage.Forward)
-        self.__urlChanged(self.history().currentItem().url())
-    
-    def home(self):
-        """
-        Public slot to move to the first page loaded.
-        """
-        homeUrl = QUrl(Preferences.getHelp("HomePage"))
-        self.setSource(homeUrl)
-        self.__urlChanged(self.history().currentItem().url())
-    
-    def reload(self):
-        """
-        Public slot to reload the current page.
-        """
-        self.triggerPageAction(QWebPage.Reload)
-    
-    def copy(self):
-        """
-        Public slot to copy the selected text.
-        """
-        self.triggerPageAction(QWebPage.Copy)
-    
-    def isForwardAvailable(self):
-        """
-        Public method to determine, if a forward move in history is possible.
-        
-        @return flag indicating move forward is possible (boolean)
-        """
-        return self.history().canGoForward()
-    
-    def isBackwardAvailable(self):
-        """
-        Public method to determine, if a backwards move in history is possible.
-        
-        @return flag indicating move backwards is possible (boolean)
-        """
-        return self.history().canGoBack()
-    
-    def __levelForZoom(self, zoom):
-        """
-        Private method determining the zoom level index given a zoom factor.
-        
-        @param zoom zoom factor (integer)
-        @return index of zoom factor (integer)
-        """
-        try:
-            index = self.__zoomLevels.index(zoom)
-        except ValueError:
-            for index in range(len(self.__zoomLevels)):
-                if zoom <= self.__zoomLevels[index]:
-                    break
-        return index
-    
-    def __applyZoom(self):
-        """
-        Private slot to apply the current zoom factor.
-        """
-        self.setZoomValue(self.__currentZoom)
-    
-    def setZoomValue(self, value, saveValue=True):
-        """
-        Public method to set the zoom value.
-        
-        @param value zoom value (integer)
-        @keyparam saveValue flag indicating to save the zoom value with the
-            zoom manager
-        @type bool
-        """
-        if value != self.zoomValue():
-            try:
-                self.setZoomFactor(value / 100.0)
-            except AttributeError:
-                self.setTextSizeMultiplier(value / 100.0)
-            self.__currentZoom = value
-            if saveValue:
-                Helpviewer.HelpWindow.HelpWindow.zoomManager().setZoomValue(
-                    self.url(), value)
-            self.zoomValueChanged.emit(value)
-    
-    def zoomValue(self):
-        """
-        Public method to get the current zoom value.
-        
-        @return zoom value (integer)
-        """
-        try:
-            val = self.zoomFactor() * 100
-        except AttributeError:
-            val = self.textSizeMultiplier() * 100
-        return int(val)
-    
-    def zoomIn(self):
-        """
-        Public slot to zoom into the page.
-        """
-        index = self.__levelForZoom(self.__currentZoom)
-        if index < len(self.__zoomLevels) - 1:
-            self.__currentZoom = self.__zoomLevels[index + 1]
-        self.__applyZoom()
-    
-    def zoomOut(self):
-        """
-        Public slot to zoom out of the page.
-        """
-        index = self.__levelForZoom(self.__currentZoom)
-        if index > 0:
-            self.__currentZoom = self.__zoomLevels[index - 1]
-        self.__applyZoom()
-    
-    def zoomReset(self):
-        """
-        Public method to reset the zoom factor.
-        """
-        index = self.__levelForZoom(HelpBrowser.ZoomLevelDefault)
-        self.__currentZoom = self.__zoomLevels[index]
-        self.__applyZoom()
-    
-    def hasSelection(self):
-        """
-        Public method to determine, if there is some text selected.
-        
-        @return flag indicating text has been selected (boolean)
-        """
-        return self.selectedText() != ""
-    
-    def findNextPrev(self, txt, case, backwards, wrap, highlightAll):
-        """
-        Public slot to find the next occurrence of a text.
-        
-        @param txt text to search for (string)
-        @param case flag indicating a case sensitive search (boolean)
-        @param backwards flag indicating a backwards search (boolean)
-        @param wrap flag indicating to wrap around (boolean)
-        @param highlightAll flag indicating to highlight all occurrences
-            (boolean)
-        @return flag indicating that a match was found (boolean)
-        """
-        findFlags = QWebPage.FindFlags()
-        if case:
-            findFlags |= QWebPage.FindCaseSensitively
-        if backwards:
-            findFlags |= QWebPage.FindBackward
-        if wrap:
-            findFlags |= QWebPage.FindWrapsAroundDocument
-        try:
-            if highlightAll:
-                findFlags |= QWebPage.HighlightAllOccurrences
-        except AttributeError:
-            pass
-        
-        return self.findText(txt, findFlags)
-    
-    def __isMediaElement(self, element):
-        """
-        Private method to check, if the given element is a media element.
-        
-        @param element element to be checked (QWebElement)
-        @return flag indicating a media element (boolean)
-        """
-        return element.tagName().lower() in ["video", "audio"]
-    
-    def contextMenuEvent(self, evt):
-        """
-        Protected method called to create a context menu.
-        
-        This method is overridden from QWebView.
-        
-        @param evt reference to the context menu event object
-            (QContextMenuEvent)
-        """
-        from .UserAgent.UserAgentMenu import UserAgentMenu
-        menu = QMenu(self)
-        
-        if self.url().toString() == "eric:speeddial":
-            # special menu for the spedd dial page
-            menu.addAction(self.mw.newTabAct)
-            menu.addAction(self.mw.newAct)
-            menu.addSeparator()
-            menu.addAction(self.mw.backAct)
-            menu.addAction(self.mw.forwardAct)
-            menu.addSeparator()
-            menu.addAction(
-                UI.PixmapCache.getIcon("plus.png"),
-                self.tr("Add New Page"), self.__addSpeedDial)
-            menu.addAction(
-                UI.PixmapCache.getIcon("preferences-general.png"),
-                self.tr("Configure Speed Dial"), self.__configureSpeedDial)
-            menu.addSeparator()
-            menu.addAction(
-                UI.PixmapCache.getIcon("reload.png"),
-                self.tr("Reload All Dials"), self.__reloadAllSpeedDials)
-            menu.addSeparator()
-            menu.addAction(
-                self.tr("Reset to Default Dials"), self.__resetSpeedDials)
-            
-            menu.exec_(evt.globalPos())
-            return
-        
-        frameAtPos = self.page().frameAt(evt.pos())
-        hit = self.page().mainFrame().hitTestContent(evt.pos())
-        if not hit.linkUrl().isEmpty():
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("openNewTab.png"),
-                self.tr("Open Link in New Tab\tCtrl+LMB"))
-            act.setData(hit.linkUrl())
-            act.triggered.connect(
-                lambda: self.__openLinkInNewTab(act))
-            menu.addSeparator()
-            menu.addAction(
-                UI.PixmapCache.getIcon("download.png"),
-                self.tr("Save Lin&k"), self.__downloadLink)
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("bookmark22.png"),
-                self.tr("Bookmark this Link"))
-            act.setData(hit.linkUrl())
-            act.triggered.connect(
-                lambda: self.__bookmarkLink(act))
-            menu.addSeparator()
-            menu.addAction(
-                UI.PixmapCache.getIcon("editCopy.png"),
-                self.tr("Copy Link to Clipboard"), self.__copyLink)
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("mailSend.png"),
-                self.tr("Send Link"))
-            act.setData(hit.linkUrl())
-            act.triggered.connect(
-                lambda: self.__sendLink(act))
-            if Preferences.getHelp("VirusTotalEnabled") and \
-               Preferences.getHelp("VirusTotalServiceKey") != "":
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("virustotal.png"),
-                    self.tr("Scan Link with VirusTotal"))
-                act.setData(hit.linkUrl())
-                act.triggered.connect(
-                    lambda: self.__virusTotal(act))
-        
-        if not hit.imageUrl().isEmpty():
-            if not menu.isEmpty():
-                menu.addSeparator()
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("openNewTab.png"),
-                self.tr("Open Image in New Tab"))
-            act.setData(hit.imageUrl())
-            act.triggered.connect(
-                lambda: self.__openLinkInNewTab(act))
-            menu.addSeparator()
-            menu.addAction(
-                UI.PixmapCache.getIcon("download.png"),
-                self.tr("Save Image"), self.__downloadImage)
-            menu.addAction(
-                self.tr("Copy Image to Clipboard"), self.__copyImage)
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("editCopy.png"),
-                self.tr("Copy Image Location to Clipboard"))
-            act.setData(hit.imageUrl().toString())
-            act.triggered.connect(
-                lambda: self.__copyLocation(act))
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("mailSend.png"),
-                self.tr("Send Image Link"))
-            act.setData(hit.imageUrl())
-            act.triggered.connect(
-                lambda: self.__sendLink(act))
-            menu.addSeparator()
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("adBlockPlus.png"),
-                self.tr("Block Image"))
-            act.setData(hit.imageUrl().toString())
-            act.triggered.connect(
-                lambda: self.__blockImage(act))
-            if Preferences.getHelp("VirusTotalEnabled") and \
-               Preferences.getHelp("VirusTotalServiceKey") != "":
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("virustotal.png"),
-                    self.tr("Scan Image with VirusTotal"))
-                act.setData(hit.imageUrl())
-                act.triggered.connect(
-                    lambda: self.__virusTotal(act))
-        
-        element = hit.element()
-        if not element.isNull():
-            if self.__isMediaElement(element):
-                if not menu.isEmpty():
-                    menu.addSeparator()
-                
-                self.__clickedMediaElement = element
-                
-                paused = element.evaluateJavaScript("this.paused")
-                muted = element.evaluateJavaScript("this.muted")
-                videoUrl = QUrl(element.evaluateJavaScript("this.currentSrc"))
-                
-                if paused:
-                    menu.addAction(
-                        UI.PixmapCache.getIcon("mediaPlaybackStart.png"),
-                        self.tr("Play"), self.__pauseMedia)
-                else:
-                    menu.addAction(
-                        UI.PixmapCache.getIcon("mediaPlaybackPause.png"),
-                        self.tr("Pause"), self.__pauseMedia)
-                if muted:
-                    menu.addAction(
-                        UI.PixmapCache.getIcon("audioVolumeHigh.png"),
-                        self.tr("Unmute"), self.__muteMedia)
-                else:
-                    menu.addAction(
-                        UI.PixmapCache.getIcon("audioVolumeMuted.png"),
-                        self.tr("Mute"), self.__muteMedia)
-                menu.addSeparator()
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("editCopy.png"),
-                    self.tr("Copy Media Address to Clipboard"))
-                act.setData(videoUrl.toString())
-                act.triggered.connect(
-                    lambda: self.__copyLocation(act))
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("mailSend.png"),
-                    self.tr("Send Media Address"))
-                act.setData(videoUrl)
-                act.triggered.connect(
-                    lambda: self.__sendLink(act))
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("download.png"),
-                    self.tr("Save Media"))
-                act.setData(videoUrl)
-                act.triggered.connect(
-                    lambda: self.__downloadMedia(act))
-            
-            if element.tagName().lower() in ["input", "textarea"]:
-                if menu.isEmpty():
-                    pageMenu = self.page().createStandardContextMenu()
-                    directionFound = False
-                    # used to detect double direction entry
-                    for act in pageMenu.actions():
-                        if act.isSeparator():
-                            menu.addSeparator()
-                            continue
-                        if act.menu():
-                            if self.pageAction(
-                                    QWebPage.SetTextDirectionDefault) in \
-                                    act.menu().actions():
-                                if directionFound:
-                                    act.setVisible(False)
-                                directionFound = True
-                            elif self.pageAction(QWebPage.ToggleBold) in \
-                                    act.menu().actions():
-                                act.setVisible(False)
-                        elif act == self.pageAction(QWebPage.InspectElement):
-                            # we have our own inspect entry
-                            act.setVisible(False)
-                        menu.addAction(act)
-                    pageMenu = None
-        
-        if not menu.isEmpty():
-            menu.addSeparator()
-        
-        self.mw.personalInformationManager().createSubMenu(menu, self, hit)
-        
-        menu.addAction(self.mw.newTabAct)
-        menu.addAction(self.mw.newAct)
-        menu.addSeparator()
-        menu.addAction(self.mw.saveAsAct)
-        menu.addSeparator()
-        
-        if frameAtPos and self.page().mainFrame() != frameAtPos:
-            self.__clickedFrame = frameAtPos
-            fmenu = QMenu(self.tr("This Frame"))
-            frameUrl = self.__clickedFrame.url()
-            if frameUrl.isValid():
-                fmenu.addAction(
-                    self.tr("Show &only this frame"),
-                    self.__loadClickedFrame)
-                act = fmenu.addAction(
-                    UI.PixmapCache.getIcon("openNewTab.png"),
-                    self.tr("Show in new &tab"))
-                act.setData(self.__clickedFrame.url())
-                act.triggered.connect(
-                    lambda: self.__openLinkInNewTab(act))
-                fmenu.addSeparator()
-            fmenu.addAction(
-                UI.PixmapCache.getIcon("print.png"),
-                self.tr("&Print"), self.__printClickedFrame)
-            fmenu.addAction(
-                UI.PixmapCache.getIcon("printPreview.png"),
-                self.tr("Print Preview"), self.__printPreviewClickedFrame)
-            fmenu.addAction(
-                UI.PixmapCache.getIcon("printPdf.png"),
-                self.tr("Print as PDF"), self.__printPdfClickedFrame)
-            fmenu.addSeparator()
-            fmenu.addAction(
-                UI.PixmapCache.getIcon("zoomIn.png"),
-                self.tr("Zoom &in"), self.__zoomInClickedFrame)
-            fmenu.addAction(
-                UI.PixmapCache.getIcon("zoomReset.png"),
-                self.tr("Zoom &reset"), self.__zoomResetClickedFrame)
-            fmenu.addAction(
-                UI.PixmapCache.getIcon("zoomOut.png"),
-                self.tr("Zoom &out"), self.__zoomOutClickedFrame)
-            fmenu.addSeparator()
-            fmenu.addAction(
-                self.tr("Show frame so&urce"),
-                self.__showClickedFrameSource)
-            
-            menu.addMenu(fmenu)
-            menu.addSeparator()
-        
-        menu.addAction(
-            UI.PixmapCache.getIcon("bookmark22.png"),
-            self.tr("Bookmark this Page"), self.addBookmark)
-        act = menu.addAction(
-            UI.PixmapCache.getIcon("mailSend.png"),
-            self.tr("Send Page Link"))
-        act.setData(self.url())
-        act.triggered.connect(
-            lambda: self.__sendLink(act))
-        menu.addSeparator()
-        self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"),
-                                             url=self.url())
-        menu.addMenu(self.__userAgentMenu)
-        menu.addSeparator()
-        menu.addAction(self.mw.backAct)
-        menu.addAction(self.mw.forwardAct)
-        menu.addAction(self.mw.homeAct)
-        menu.addSeparator()
-        menu.addAction(self.mw.zoomInAct)
-        menu.addAction(self.mw.zoomResetAct)
-        menu.addAction(self.mw.zoomOutAct)
-        menu.addSeparator()
-        if self.selectedText():
-            menu.addAction(self.mw.copyAct)
-            act = menu.addAction(
-                UI.PixmapCache.getIcon("mailSend.png"),
-                self.tr("Send Text"))
-            act.setData(self.selectedText())
-            act.triggered.connect(
-                lambda: self.__sendLink(act))
-        menu.addAction(self.mw.findAct)
-        menu.addSeparator()
-        if self.selectedText():
-            self.__searchMenu = menu.addMenu(self.tr("Search with..."))
-            
-            from .OpenSearch.OpenSearchEngineAction import \
-                OpenSearchEngineAction
-            engineNames = self.mw.openSearchManager().allEnginesNames()
-            for engineName in engineNames:
-                engine = self.mw.openSearchManager().engine(engineName)
-                act = OpenSearchEngineAction(engine, self.__searchMenu)
-                act.setData(engineName)
-                self.__searchMenu.addAction(act)
-            self.__searchMenu.triggered.connect(self.__searchRequested)
-            
-            menu.addSeparator()
-            
-            from .HelpLanguagesDialog import HelpLanguagesDialog
-            languages = Preferences.toList(
-                Preferences.Prefs.settings.value(
-                    "Help/AcceptLanguages",
-                    HelpLanguagesDialog.defaultAcceptLanguages()))
-            if languages:
-                language = languages[0]
-                langCode = language.split("[")[1][:2]
-                googleTranslatorUrl = QUrl(
-                    "http://translate.google.com/#auto|{0}|{1}".format(
-                        langCode, self.selectedText()))
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("translate.png"),
-                    self.tr("Google Translate"))
-                act.setData(googleTranslatorUrl)
-                act.triggered.connect(
-                    lambda: self.__openLinkInNewTab(act))
-                wiktionaryUrl = QUrl(
-                    "http://{0}.wiktionary.org/wiki/Special:Search?search={1}"
-                    .format(langCode, self.selectedText()))
-                act = menu.addAction(
-                    UI.PixmapCache.getIcon("wikipedia.png"),
-                    self.tr("Dictionary"))
-                act.setData(wiktionaryUrl)
-                act.triggered.connect(
-                    lambda: self.__openLinkInNewTab(act))
-                menu.addSeparator()
-            
-            guessedUrl = QUrl.fromUserInput(self.selectedText().strip())
-            if self.__isUrlValid(guessedUrl):
-                act = menu.addAction(self.tr("Go to web address"))
-                act.setData(guessedUrl)
-                act.triggered.connect(
-                    lambda: self.__openLinkInNewTab(act))
-                menu.addSeparator()
-        
-        element = hit.element()
-        if not element.isNull() and \
-           element.tagName().lower() == "input" and \
-           element.attribute("type", "text") == "text":
-            act = menu.addAction(
-                self.tr("Add to web search toolbar"))
-            act.setData(element)
-            act.triggered.connect(
-                lambda: self.__addSearchEngine(act))
-            menu.addSeparator()
-        
-        menu.addAction(
-            UI.PixmapCache.getIcon("webInspector.png"),
-            self.tr("Web Inspector..."), self.__webInspector)
-        
-        menu.exec_(evt.globalPos())
-    
-    def __isUrlValid(self, url):
-        """
-        Private method to check a URL for validity.
-        
-        @param url URL to be checked (QUrl)
-        @return flag indicating a valid URL (boolean)
-        """
-        return url.isValid() and \
-            bool(url.host()) and \
-            bool(url.scheme()) and \
-            "." in url.host()
-    
-    def __openLinkInNewTab(self, act):
-        """
-        Private method called by the context menu to open a link in a new
-        window.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        url = act.data()
-        if url.isEmpty():
-            return
-        
-        self.ctrlPressed = True
-        self.setSource(url)
-        self.ctrlPressed = False
-    
-    def __bookmarkLink(self, act):
-        """
-        Private slot to bookmark a link via the context menu.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        url = act.data()
-        if url.isEmpty():
-            return
-        
-        from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog
-        dlg = AddBookmarkDialog()
-        dlg.setUrl(bytes(url.toEncoded()).decode())
-        dlg.exec_()
-    
-    def __sendLink(self, act):
-        """
-        Private slot to send a link via email.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        data = act.data()
-        if isinstance(data, QUrl) and data.isEmpty():
-            return
-        
-        if isinstance(data, QUrl):
-            data = data.toString()
-        QDesktopServices.openUrl(QUrl("mailto:?body=" + data))
-    
-    def __downloadLink(self):
-        """
-        Private slot to download a link and save it to disk.
-        """
-        self.pageAction(QWebPage.DownloadLinkToDisk).trigger()
-    
-    def __copyLink(self):
-        """
-        Private slot to copy a link to the clipboard.
-        """
-        self.pageAction(QWebPage.CopyLinkToClipboard).trigger()
-    
-    def __downloadImage(self):
-        """
-        Private slot to download an image and save it to disk.
-        """
-        self.pageAction(QWebPage.DownloadImageToDisk).trigger()
-    
-    def __copyImage(self):
-        """
-        Private slot to copy an image to the clipboard.
-        """
-        self.pageAction(QWebPage.CopyImageToClipboard).trigger()
-    
-    def __copyLocation(self, act):
-        """
-        Private slot to copy an image or media location to the clipboard.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        url = act.data()
-        QApplication.clipboard().setText(url)
-    
-    def __blockImage(self, act):
-        """
-        Private slot to add a block rule for an image URL.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        import Helpviewer.HelpWindow
-        url = act.data()
-        dlg = Helpviewer.HelpWindow.HelpWindow.adBlockManager().showDialog()
-        dlg.addCustomRule(url)
-    
-    def __downloadMedia(self, act):
-        """
-        Private slot to download a media and save it to disk.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        url = act.data()
-        self.mw.downloadManager().download(url, True, mainWindow=self.mw)
-    
-    def __pauseMedia(self):
-        """
-        Private slot to pause or play the selected media.
-        """
-        paused = self.__clickedMediaElement.evaluateJavaScript("this.paused")
-        
-        if paused:
-            self.__clickedMediaElement.evaluateJavaScript("this.play()")
-        else:
-            self.__clickedMediaElement.evaluateJavaScript("this.pause()")
-    
-    def __muteMedia(self):
-        """
-        Private slot to (un)mute the selected media.
-        """
-        muted = self.__clickedMediaElement.evaluateJavaScript("this.muted")
-        
-        if muted:
-            self.__clickedMediaElement.evaluateJavaScript("this.muted = false")
-        else:
-            self.__clickedMediaElement.evaluateJavaScript("this.muted = true")
-    
-    def __virusTotal(self, act):
-        """
-        Private slot to scan the selected URL with VirusTotal.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        url = act.data()
-        self.mw.requestVirusTotalScan(url)
-    
-    def __searchRequested(self, act):
-        """
-        Private slot to search for some text with a selected search engine.
-        
-        @param act reference to the action that triggered this slot (QAction)
-        """
-        searchText = self.selectedText()
-        
-        if not searchText:
-            return
-        
-        engineName = act.data()
-        if engineName:
-            engine = self.mw.openSearchManager().engine(engineName)
-            self.search.emit(engine.searchUrl(searchText))
-    
-    def __addSearchEngine(self, act):
-        """
-        Private slot to add a new search engine.
-        
-        @param act reference to the action that triggered
-        @type QAction
-        """
-        element = act.data()
-        elementName = element.attribute("name")
-        formElement = QWebElement(element)
-        while formElement.tagName().lower() != "form":
-            formElement = formElement.parent()
-        
-        if formElement.isNull() or \
-           formElement.attribute("action") == "":
-            return
-        
-        method = formElement.attribute("method", "get").lower()
-        if method != "get":
-            E5MessageBox.warning(
-                self,
-                self.tr("Method not supported"),
-                self.tr(
-                    """{0} method is not supported.""").format(method.upper()))
-            return
-        
-        searchUrl = QUrl(self.page().mainFrame().baseUrl().resolved(
-            QUrl(formElement.attribute("action"))))
-        
-        if qVersionTuple() >= (5, 0, 0):
-            from PyQt5.QtCore import QUrlQuery
-            searchUrlQuery = QUrlQuery(searchUrl)
-        searchEngines = {}
-        inputFields = formElement.findAll("input")
-        for inputField in inputFields.toList():
-            type_ = inputField.attribute("type", "text")
-            name = inputField.attribute("name")
-            value = inputField.evaluateJavaScript("this.value")
-            
-            if type_ == "submit":
-                searchEngines[value] = name
-            elif type_ == "text":
-                if inputField == element:
-                    value = "{searchTerms}"
-                if qVersionTuple() >= (5, 0, 0):
-                    searchUrlQuery.addQueryItem(name, value)
-                else:
-                    searchUrl.addQueryItem(name, value)
-            elif type_ == "checkbox" or type_ == "radio":
-                if inputField.evaluateJavaScript("this.checked"):
-                    if qVersionTuple() >= (5, 0, 0):
-                        searchUrlQuery.addQueryItem(name, value)
-                    else:
-                        searchUrl.addQueryItem(name, value)
-            elif type_ == "hidden":
-                if qVersionTuple() >= (5, 0, 0):
-                    searchUrlQuery.addQueryItem(name, value)
-                else:
-                    searchUrl.addQueryItem(name, value)
-        
-        selectFields = formElement.findAll("select")
-        for selectField in selectFields.toList():
-            name = selectField.attribute("name")
-            selectedIndex = selectField.evaluateJavaScript(
-                "this.selectedIndex")
-            if selectedIndex == -1:
-                continue
-            
-            options = selectField.findAll("option")
-            value = options.at(selectedIndex).toPlainText()
-            if qVersionTuple() >= (5, 0, 0):
-                searchUrlQuery.addQueryItem(name, value)
-            else:
-                searchUrl.addQueryItem(name, value)
-        
-        ok = True
-        if len(searchEngines) > 1:
-            searchEngine, ok = QInputDialog.getItem(
-                self,
-                self.tr("Search engine"),
-                self.tr("Choose the desired search engine"),
-                sorted(searchEngines.keys()), 0, False)
-            
-            if not ok:
-                return
-            
-            if searchEngines[searchEngine] != "":
-                if qVersionTuple() >= (5, 0, 0):
-                    searchUrlQuery.addQueryItem(
-                        searchEngines[searchEngine], searchEngine)
-                else:
-                    searchUrl.addQueryItem(
-                        searchEngines[searchEngine], searchEngine)
-        engineName = ""
-        labels = formElement.findAll('label[for="{0}"]'.format(elementName))
-        if labels.count() > 0:
-            engineName = labels.at(0).toPlainText()
-        
-        engineName, ok = QInputDialog.getText(
-            self,
-            self.tr("Engine name"),
-            self.tr("Enter a name for the engine"),
-            QLineEdit.Normal,
-            engineName)
-        if not ok:
-            return
-        
-        if qVersionTuple() >= (5, 0, 0):
-            searchUrl.setQuery(searchUrlQuery)
-        
-        from .OpenSearch.OpenSearchEngine import OpenSearchEngine
-        engine = OpenSearchEngine()
-        engine.setName(engineName)
-        engine.setDescription(engineName)
-        if qVersionTuple() >= (5, 0, 0):
-            engine.setSearchUrlTemplate(
-                searchUrl.toDisplayString(QUrl.FullyDecoded))
-        else:
-            engine.setSearchUrlTemplate(searchUrl.toString())
-        engine.setImage(self.icon().pixmap(16, 16).toImage())
-        
-        self.mw.openSearchManager().addEngine(engine)
-    
-    def __webInspector(self):
-        """
-        Private slot to show the web inspector window.
-        """
-        if self.__inspector is None:
-            from .HelpInspector import HelpInspector
-            self.__inspector = HelpInspector()
-            self.__inspector.setPage(self.page())
-            self.__inspector.show()
-        elif self.__inspector.isVisible():
-            self.__inspector.hide()
-        else:
-            self.__inspector.show()
-    
-    def closeWebInspector(self):
-        """
-        Public slot to close the web inspector.
-        """
-        if self.__inspector is not None:
-            if self.__inspector.isVisible():
-                self.__inspector.hide()
-            self.__inspector.deleteLater()
-            self.__inspector = None
-    
-    def addBookmark(self):
-        """
-        Public slot to bookmark the current page.
-        """
-        from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog
-        dlg = AddBookmarkDialog()
-        dlg.setUrl(bytes(self.url().toEncoded()).decode())
-        dlg.setTitle(self.title())
-        meta = self.page().mainFrame().metaData()
-        if "description" in meta:
-            dlg.setDescription(meta["description"][0])
-        dlg.exec_()
-    
-    def dragEnterEvent(self, evt):
-        """
-        Protected method called by a drag enter event.
-        
-        @param evt reference to the drag enter event (QDragEnterEvent)
-        """
-        evt.acceptProposedAction()
-    
-    def dragMoveEvent(self, evt):
-        """
-        Protected method called by a drag move event.
-        
-        @param evt reference to the drag move event (QDragMoveEvent)
-        """
-        evt.ignore()
-        if evt.source() != self:
-            if len(evt.mimeData().urls()) > 0:
-                evt.acceptProposedAction()
-            else:
-                url = QUrl(evt.mimeData().text())
-                if url.isValid():
-                    evt.acceptProposedAction()
-        
-        if not evt.isAccepted():
-            super(HelpBrowser, self).dragMoveEvent(evt)
-    
-    def dropEvent(self, evt):
-        """
-        Protected method called by a drop event.
-        
-        @param evt reference to the drop event (QDropEvent)
-        """
-        super(HelpBrowser, self).dropEvent(evt)
-        if not evt.isAccepted() and \
-           evt.source() != self and \
-           evt.possibleActions() & Qt.CopyAction:
-            url = QUrl()
-            if len(evt.mimeData().urls()) > 0:
-                url = evt.mimeData().urls()[0]
-            if not url.isValid():
-                url = QUrl(evt.mimeData().text())
-            if url.isValid():
-                self.setSource(url)
-                evt.acceptProposedAction()
-    
-    def mousePressEvent(self, evt):
-        """
-        Protected method called by a mouse press event.
-        
-        @param evt reference to the mouse event (QMouseEvent)
-        """
-        self.mw.setEventMouseButtons(evt.buttons())
-        self.mw.setEventKeyboardModifiers(evt.modifiers())
-        
-        if evt.button() == Qt.XButton1:
-            self.pageAction(QWebPage.Back).trigger()
-        elif evt.button() == Qt.XButton2:
-            self.pageAction(QWebPage.Forward).trigger()
-        else:
-            super(HelpBrowser, self).mousePressEvent(evt)
-    
-    def mouseReleaseEvent(self, evt):
-        """
-        Protected method called by a mouse release event.
-        
-        @param evt reference to the mouse event (QMouseEvent)
-        """
-        accepted = evt.isAccepted()
-        self.__page.event(evt)
-        if not evt.isAccepted() and \
-           self.mw.eventMouseButtons() & Qt.MidButton:
-            url = QUrl(QApplication.clipboard().text(QClipboard.Selection))
-            if not url.isEmpty() and \
-               url.isValid() and \
-               url.scheme() != "":
-                self.mw.setEventMouseButtons(Qt.NoButton)
-                self.mw.setEventKeyboardModifiers(Qt.NoModifier)
-                self.setSource(url)
-        evt.setAccepted(accepted)
-    
-    def wheelEvent(self, evt):
-        """
-        Protected method to handle wheel events.
-        
-        @param evt reference to the wheel event (QWheelEvent)
-        """
-        if qVersionTuple() >= (5, 0, 0):
-            delta = evt.angleDelta().y()
-        else:
-            delta = evt.delta()
-        if evt.modifiers() & Qt.ControlModifier:
-            if delta < 0:
-                self.zoomOut()
-            elif delta > 0:
-                self.zoomIn()
-            evt.accept()
-            return
-        
-        if evt.modifiers() & Qt.ShiftModifier:
-            if delta < 0:
-                self.backward()
-            elif delta > 0:
-                self.forward()
-            evt.accept()
-            return
-        
-        super(HelpBrowser, self).wheelEvent(evt)
-    
-    def keyPressEvent(self, evt):
-        """
-        Protected method called by a key press.
-        
-        @param evt reference to the key event (QKeyEvent)
-        """
-        if self.mw.personalInformationManager().viewKeyPressEvent(self, evt):
-            return
-        
-        if self.__enableAccessKeys:
-            self.__accessKeysPressed = (
-                evt.modifiers() == Qt.ControlModifier and
-                evt.key() == Qt.Key_Control)
-            if not self.__accessKeysPressed:
-                if self.__checkForAccessKey(evt):
-                    self.__hideAccessKeys()
-                    evt.accept()
-                    return
-                self.__hideAccessKeys()
-            else:
-                QTimer.singleShot(300, self.__accessKeyShortcut)
-        
-        self.ctrlPressed = (evt.key() == Qt.Key_Control)
-        super(HelpBrowser, self).keyPressEvent(evt)
-    
-    def keyReleaseEvent(self, evt):
-        """
-        Protected method called by a key release.
-        
-        @param evt reference to the key event (QKeyEvent)
-        """
-        if self.__enableAccessKeys:
-            self.__accessKeysPressed = evt.key() == Qt.Key_Control
-        
-        self.ctrlPressed = False
-        super(HelpBrowser, self).keyReleaseEvent(evt)
-    
-    def focusOutEvent(self, evt):
-        """
-        Protected method called by a focus out event.
-        
-        @param evt reference to the focus event (QFocusEvent)
-        """
-        if self.__accessKeysPressed:
-            self.__hideAccessKeys()
-            self.__accessKeysPressed = False
-        
-        super(HelpBrowser, self).focusOutEvent(evt)
-    
-    def event(self, evt):
-        """
-        Public method handling events.
-        
-        @param evt reference to the event (QEvent)
-        @return flag indicating, if the event was handled (boolean)
-        """
-        if evt.type() == QEvent.Gesture:
-            self.gestureEvent(evt)
-            return True
-        
-        return super(HelpBrowser, self).event(evt)
-    
-    def gestureEvent(self, evt):
-        """
-        Protected method handling gesture events.
-        
-        @param evt reference to the gesture event (QGestureEvent
-        """
-        pinch = evt.gesture(Qt.PinchGesture)
-        if pinch:
-            if pinch.state() == Qt.GestureStarted:
-                pinch.setTotalScaleFactor(self.__currentZoom / 100.0)
-            elif pinch.state() == Qt.GestureUpdated:
-                scaleFactor = pinch.totalScaleFactor()
-                self.__currentZoom = int(scaleFactor * 100)
-                self.__applyZoom()
-            evt.accept()
-    
-    def clearHistory(self):
-        """
-        Public slot to clear the history.
-        """
-        self.history().clear()
-        self.__urlChanged(self.history().currentItem().url())
-    
-    ###########################################################################
-    ## Signal converters below
-    ###########################################################################
-    
-    def __urlChanged(self, url):
-        """
-        Private slot to handle the urlChanged signal.
-        
-        @param url the new url (QUrl)
-        """
-        self.sourceChanged.emit(url)
-        
-        self.forwardAvailable.emit(self.isForwardAvailable())
-        self.backwardAvailable.emit(self.isBackwardAvailable())
-    
-    def __statusBarMessage(self, text):
-        """
-        Private slot to handle the statusBarMessage signal.
-        
-        @param text text to be shown in the status bar (string)
-        """
-        self.mw.statusBar().showMessage(text)
-    
-    def __linkHovered(self, link, title, textContent):
-        """
-        Private slot to handle the linkHovered signal.
-        
-        @param link the URL of the link (string)
-        @param title the link title (string)
-        @param textContent text content of the link (string)
-        """
-        self.highlighted.emit(link)
-    
-    ###########################################################################
-    ## Signal handlers below
-    ###########################################################################
-    
-    def __loadStarted(self):
-        """
-        Private method to handle the loadStarted signal.
-        """
-        self.__isLoading = True
-        self.__progress = 0
-    
-    def __loadProgress(self, progress):
-        """
-        Private method to handle the loadProgress signal.
-        
-        @param progress progress value (integer)
-        """
-        self.__progress = progress
-    
-    def __loadFinished(self, ok):
-        """
-        Private method to handle the loadFinished signal.
-        
-        @param ok flag indicating the result (boolean)
-        """
-        self.__isLoading = False
-        self.__progress = 0
-        
-        if Preferences.getHelp("ClickToFlashEnabled"):
-            # this is a hack to make the ClickToFlash button appear
-            self.zoomIn()
-            self.zoomOut()
-        
-        zoomValue = Helpviewer.HelpWindow.HelpWindow.zoomManager()\
-            .zoomValue(self.url())
-        self.setZoomValue(zoomValue)
-        
-        if ok:
-            self.mw.adBlockManager().page().hideBlockedPageEntries(self.page())
-            self.mw.passwordManager().fill(self.page())
-    
-    def isLoading(self):
-        """
-        Public method to get the loading state.
-        
-        @return flag indicating the loading state (boolean)
-        """
-        return self.__isLoading
-    
-    def progress(self):
-        """
-        Public method to get the load progress.
-        
-        @return load progress (integer)
-        """
-        return self.__progress
-    
-    def saveAs(self):
-        """
-        Public method to save the current page to a file.
-        """
-        url = self.url()
-        if url.isEmpty():
-            return
-        
-        self.mw.downloadManager().download(url, True, mainWindow=self.mw)
-    
-    def __unsupportedContent(self, reply, requestFilename=None,
-                             download=False):
-        """
-        Private slot to handle the unsupportedContent signal.
-        
-        @param reply reference to the reply object (QNetworkReply)
-        @keyparam requestFilename indicating to ask for a filename
-            (boolean or None). If it is None, the behavior is determined
-            by a configuration option.
-        @keyparam download flag indicating a download operation (boolean)
-        """
-        if reply is None:
-            return
-        
-        replyUrl = reply.url()
-        
-        if replyUrl.scheme() == "abp":
-            return
-        
-        if reply.error() == QNetworkReply.NoError:
-            if reply.header(QNetworkRequest.ContentTypeHeader):
-                self.mw.downloadManager().handleUnsupportedContent(
-                    reply, webPage=self.page(), mainWindow=self.mw)
-                return
-        
-        replyUrl = reply.url()
-        if replyUrl.isEmpty():
-            return
-        
-        notFoundFrame = self.page().mainFrame()
-        if notFoundFrame is None:
-            return
-        
-        if reply.header(QNetworkRequest.ContentTypeHeader):
-            data = reply.readAll()
-            if contentSniff(data):
-                notFoundFrame.setHtml(str(data, encoding="utf-8"), replyUrl)
-                return
-        
-        urlString = bytes(replyUrl.toEncoded()).decode()
-        title = self.tr("Error loading page: {0}").format(urlString)
-        htmlFile = QFile(":/html/notFoundPage.html")
-        htmlFile.open(QFile.ReadOnly)
-        html = htmlFile.readAll()
-        pixmap = qApp.style()\
-            .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48)
-        imageBuffer = QBuffer()
-        imageBuffer.open(QIODevice.ReadWrite)
-        if pixmap.save(imageBuffer, "PNG"):
-            html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64())
-        pixmap = qApp.style()\
-            .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16)
-        imageBuffer = QBuffer()
-        imageBuffer.open(QIODevice.ReadWrite)
-        if pixmap.save(imageBuffer, "PNG"):
-            html = html.replace("@FAVICON@", imageBuffer.buffer().toBase64())
-        html = html.replace("@TITLE@", title.encode("utf8"))
-        html = html.replace("@H1@", reply.errorString().encode("utf8"))
-        html = html.replace(
-            "@H2@", self.tr("When connecting to: {0}.")
-            .format(urlString).encode("utf8"))
-        html = html.replace(
-            "@LI-1@",
-            self.tr("Check the address for errors such as "
-                    "<b>ww</b>.example.org instead of "
-                    "<b>www</b>.example.org").encode("utf8"))
-        html = html.replace(
-            "@LI-2@",
-            self.tr("If the address is correct, try checking the network "
-                    "connection.").encode("utf8"))
-        html = html.replace(
-            "@LI-3@",
-            self.tr(
-                "If your computer or network is protected by a firewall "
-                "or proxy, make sure that the browser is permitted to "
-                "access the network.").encode("utf8"))
-        html = html.replace(
-            "@LI-4@",
-            self.tr("If your cache policy is set to offline browsing,"
-                    "only pages in the local cache are available.")
-            .encode("utf8"))
-        html = html.replace(
-            "@BUTTON@", self.tr("Try Again").encode("utf8"))
-        notFoundFrame.setHtml(bytes(html).decode("utf8"), replyUrl)
-        self.mw.historyManager().removeHistoryEntry(replyUrl, self.title())
-        self.loadFinished.emit(False)
-    
-    def __featurePermissionRequested(self, frame, feature):
-        """
-        Private slot handling a feature permission request.
-        
-        @param frame frame sending the request
-        @type QWebFrame
-        @param feature requested feature
-        @type QWebPage.Feature
-        """
-        manager = Helpviewer.HelpWindow.HelpWindow.featurePermissionManager()
-        manager.requestFeaturePermission(self.page(), frame, feature)
-    
-    def __downloadRequested(self, request):
-        """
-        Private slot to handle a download request.
-        
-        @param request reference to the request object (QNetworkRequest)
-        """
-        self.mw.downloadManager().download(request, mainWindow=self.mw)
-    
-    def __databaseQuotaExceeded(self, frame, databaseName):
-        """
-        Private slot to handle the case, where the database quota is exceeded.
-        
-        @param frame reference to the frame (QWebFrame)
-        @param databaseName name of the web database (string)
-        """
-        securityOrigin = frame.securityOrigin()
-        if securityOrigin.databaseQuota() > 0 and \
-           securityOrigin.databaseUsage() == 0:
-            # cope with a strange behavior of Qt 4.6, if a database is
-            # accessed for the first time
-            return
-        
-        res = E5MessageBox.yesNo(
-            self,
-            self.tr("Web Database Quota"),
-            self.tr(
-                """<p>The database quota of <strong>{0}</strong> has"""
-                """ been exceeded while accessing database <strong>{1}"""
-                """</strong>.</p><p>Shall it be changed?</p>""")
-            .format(self.__dataString(securityOrigin.databaseQuota()),
-                    databaseName),
-            yesDefault=True)
-        if res:
-            newQuota, ok = QInputDialog.getInt(
-                self,
-                self.tr("New Web Database Quota"),
-                self.tr(
-                    "Enter the new quota in MB (current = {0}, used = {1}; "
-                    "step size = 5 MB):"
-                    .format(
-                        self.__dataString(securityOrigin.databaseQuota()),
-                        self.__dataString(securityOrigin.databaseUsage()))),
-                securityOrigin.databaseQuota() // (1024 * 1024),
-                0, 2147483647, 5)
-            if ok:
-                securityOrigin.setDatabaseQuota(newQuota * 1024 * 1024)
-    
-    def __dataString(self, size):
-        """
-        Private method to generate a formatted data string.
-        
-        @param size size to be formatted (integer)
-        @return formatted data string (string)
-        """
-        unit = ""
-        if size < 1024:
-            unit = self.tr("bytes")
-        elif size < 1024 * 1024:
-            size /= 1024
-            unit = self.tr("kB")
-        else:
-            size /= 1024 * 1024
-            unit = self.tr("MB")
-        return "{0:.1f} {1}".format(size, unit)
-    
-    ###########################################################################
-    ## Access key related methods below
-    ###########################################################################
-    
-    def __accessKeyShortcut(self):
-        """
-        Private slot to switch the display of access keys.
-        """
-        if not self.hasFocus() or \
-           not self.__accessKeysPressed or \
-           not self.__enableAccessKeys:
-            return
-        
-        if self.__accessKeyLabels:
-            self.__hideAccessKeys()
-        else:
-            self.__showAccessKeys()
-        
-        self.__accessKeysPressed = False
-    
-    def __checkForAccessKey(self, evt):
-        """
-        Private method to check the existence of an access key and activate the
-        corresponding link.
-        
-        @param evt reference to the key event (QKeyEvent)
-        @return flag indicating, if the event was handled (boolean)
-        """
-        if not self.__accessKeyLabels:
-            return False
-        
-        text = evt.text()
-        if not text:
-            return False
-        
-        key = text[0].upper()
-        handled = False
-        if key in self.__accessKeyNodes:
-            element = self.__accessKeyNodes[key]
-            p = element.geometry().center()
-            frame = element.webFrame()
-            p -= frame.scrollPosition()
-            frame = frame.parentFrame()
-            while frame and frame != self.page().mainFrame():
-                p -= frame.scrollPosition()
-                frame = frame.parentFrame()
-            pevent = QMouseEvent(
-                QEvent.MouseButtonPress, p, Qt.LeftButton,
-                Qt.MouseButtons(Qt.NoButton),
-                Qt.KeyboardModifiers(Qt.NoModifier))
-            qApp.sendEvent(self, pevent)
-            revent = QMouseEvent(
-                QEvent.MouseButtonRelease, p, Qt.LeftButton,
-                Qt.MouseButtons(Qt.NoButton),
-                Qt.KeyboardModifiers(Qt.NoModifier))
-            qApp.sendEvent(self, revent)
-            handled = True
-        
-        return handled
-    
-    def __hideAccessKeys(self):
-        """
-        Private slot to hide the access key labels.
-        """
-        if self.__accessKeyLabels:
-            for label in self.__accessKeyLabels:
-                label.hide()
-                label.deleteLater()
-            self.__accessKeyLabels = []
-            self.__accessKeyNodes = {}
-            self.update()
-    
-    def __showAccessKeys(self):
-        """
-        Private method to show the access key labels.
-        """
-        supportedElements = [
-            "input", "a", "area", "button", "label", "legend", "textarea",
-        ]
-        unusedKeys = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" \
-            " 0 1 2 3 4 5 6 7 8 9".split()
-        
-        viewport = QRect(self.__page.mainFrame().scrollPosition(),
-                         self.__page.viewportSize())
-        # Priority first goes to elements with accesskey attributes
-        alreadyLabeled = []
-        for elementType in supportedElements:
-            result = self.page().mainFrame().findAllElements(elementType)\
-                .toList()
-            for element in result:
-                geometry = element.geometry()
-                if geometry.size().isEmpty() or \
-                   not viewport.contains(geometry.topLeft()):
-                    continue
-                
-                accessKeyAttribute = element.attribute("accesskey").upper()
-                if not accessKeyAttribute:
-                    continue
-                
-                accessKey = ""
-                i = 0
-                while i < len(accessKeyAttribute):
-                    if accessKeyAttribute[i] in unusedKeys:
-                        accessKey = accessKeyAttribute[i]
-                        break
-                    i += 2
-                if accessKey == "":
-                    continue
-                unusedKeys.remove(accessKey)
-                self.__makeAccessLabel(accessKey, element)
-                alreadyLabeled.append(element)
-        
-        # Pick an access key first from the letters in the text and then
-        # from the list of unused access keys
-        for elementType in supportedElements:
-            result = self.page().mainFrame().findAllElements(elementType)\
-                .toList()
-            for element in result:
-                geometry = element.geometry()
-                if not unusedKeys or \
-                   element in alreadyLabeled or \
-                   geometry.size().isEmpty() or \
-                   not viewport.contains(geometry.topLeft()):
-                    continue
-                
-                accessKey = ""
-                text = element.toPlainText().upper()
-                for c in text:
-                    if c in unusedKeys:
-                        accessKey = c
-                        break
-                if accessKey == "":
-                    accessKey = unusedKeys[0]
-                unusedKeys.remove(accessKey)
-                self.__makeAccessLabel(accessKey, element)
-    
-    def __makeAccessLabel(self, accessKey, element):
-        """
-        Private method to generate the access label for an element.
-        
-        @param accessKey access key to generate the label for (str)
-        @param element reference to the web element to create the label for
-            (QWebElement)
-        """
-        label = QLabel(self)
-        label.setText("<qt><b>{0}</b></qt>".format(accessKey))
-        
-        p = QToolTip.palette()
-        color = QColor(Qt.yellow).lighter(150)
-        color.setAlpha(175)
-        p.setColor(QPalette.Window, color)
-        label.setPalette(p)
-        label.setAutoFillBackground(True)
-        label.setFrameStyle(QFrame.Box | QFrame.Plain)
-        point = element.geometry().center()
-        point -= self.__page.mainFrame().scrollPosition()
-        label.move(point)
-        label.show()
-        point.setX(point.x() - label.width() // 2)
-        label.move(point)
-        self.__accessKeyLabels.append(label)
-        self.__accessKeyNodes[accessKey] = element
-    
-    ###########################################################################
-    ## Miscellaneous methods below
-    ###########################################################################
-    
-    def createWindow(self, windowType):
-        """
-        Public method called, when a new window should be created.
-        
-        @param windowType type of the requested window (QWebPage.WebWindowType)
-        @return reference to the created browser window (HelpBrowser)
-        """
-        self.mw.newTab(addNextTo=self)
-        return self.mw.currentBrowser()
-    
-    def preferencesChanged(self):
-        """
-        Public method to indicate a change of the settings.
-        """
-        self.__enableAccessKeys = Preferences.getHelp("AccessKeysEnabled")
-        if not self.__enableAccessKeys:
-            self.__hideAccessKeys()
-        
-        self.reload()
-    
-    ###########################################################################
-    ## RSS related methods below
-    ###########################################################################
-    
-    def checkRSS(self):
-        """
-        Public method to check, if the loaded page contains feed links.
-        
-        @return flag indicating the existence of feed links (boolean)
-        """
-        self.__rss = []
-        
-        frame = self.page().mainFrame()
-        linkElementsList = frame.findAllElements("link").toList()
-        
-        for linkElement in linkElementsList:
-            # only atom+xml and rss+xml will be processed
-            if linkElement.attribute("rel") != "alternate" or \
-               (linkElement.attribute("type") != "application/rss+xml" and
-                    linkElement.attribute("type") != "application/atom+xml"):
-                continue
-            
-            title = linkElement.attribute("title")
-            href = linkElement.attribute("href")
-            if href == "" or title == "":
-                continue
-            self.__rss.append((title, href))
-        
-        return len(self.__rss) > 0
-    
-    def getRSS(self):
-        """
-        Public method to get the extracted RSS feeds.
-        
-        @return list of RSS feeds (list of tuples of two strings)
-        """
-        return self.__rss
-    
-    def hasRSS(self):
-        """
-        Public method to check, if the loaded page has RSS links.
-        
-        @return flag indicating the presence of RSS links (boolean)
-        """
-        return len(self.__rss) > 0
-    
-    ###########################################################################
-    ## Clicked Frame slots
-    ###########################################################################
-    
-    def __loadClickedFrame(self):
-        """
-        Private slot to load the selected frame only.
-        """
-        self.setSource(self.__clickedFrame.url())
-    
-    def __printClickedFrame(self):
-        """
-        Private slot to print the selected frame.
-        """
-        printer = QPrinter(mode=QPrinter.HighResolution)
-        if Preferences.getPrinter("ColorMode"):
-            printer.setColorMode(QPrinter.Color)
-        else:
-            printer.setColorMode(QPrinter.GrayScale)
-        if Preferences.getPrinter("FirstPageFirst"):
-            printer.setPageOrder(QPrinter.FirstPageFirst)
-        else:
-            printer.setPageOrder(QPrinter.LastPageFirst)
-        printer.setPageMargins(
-            Preferences.getPrinter("LeftMargin") * 10,
-            Preferences.getPrinter("TopMargin") * 10,
-            Preferences.getPrinter("RightMargin") * 10,
-            Preferences.getPrinter("BottomMargin") * 10,
-            QPrinter.Millimeter
-        )
-        printerName = Preferences.getPrinter("PrinterName")
-        if printerName:
-            printer.setPrinterName(printerName)
-        
-        printDialog = QPrintDialog(printer, self)
-        if printDialog.exec_() == QDialog.Accepted:
-            try:
-                self.__clickedFrame.print_(printer)
-            except AttributeError:
-                E5MessageBox.critical(
-                    self,
-                    self.tr("eric6 Web Browser"),
-                    self.tr(
-                        """<p>Printing is not available due to a bug in"""
-                        """ PyQt5. Please upgrade.</p>"""))
-    
-    def __printPreviewClickedFrame(self):
-        """
-        Private slot to show a print preview of the clicked frame.
-        """
-        from PyQt5.QtPrintSupport import QPrintPreviewDialog
-        
-        printer = QPrinter(mode=QPrinter.HighResolution)
-        if Preferences.getPrinter("ColorMode"):
-            printer.setColorMode(QPrinter.Color)
-        else:
-            printer.setColorMode(QPrinter.GrayScale)
-        if Preferences.getPrinter("FirstPageFirst"):
-            printer.setPageOrder(QPrinter.FirstPageFirst)
-        else:
-            printer.setPageOrder(QPrinter.LastPageFirst)
-        printer.setPageMargins(
-            Preferences.getPrinter("LeftMargin") * 10,
-            Preferences.getPrinter("TopMargin") * 10,
-            Preferences.getPrinter("RightMargin") * 10,
-            Preferences.getPrinter("BottomMargin") * 10,
-            QPrinter.Millimeter
-        )
-        printerName = Preferences.getPrinter("PrinterName")
-        if printerName:
-            printer.setPrinterName(printerName)
-        
-        preview = QPrintPreviewDialog(printer, self)
-        preview.paintRequested.connect(self.__generatePrintPreviewClickedFrame)
-        preview.exec_()
-    
-    def __generatePrintPreviewClickedFrame(self, printer):
-        """
-        Private slot to generate a print preview of the clicked frame.
-        
-        @param printer reference to the printer object (QPrinter)
-        """
-        try:
-            self.__clickedFrame.print_(printer)
-        except AttributeError:
-            E5MessageBox.critical(
-                self,
-                self.tr("eric6 Web Browser"),
-                self.tr(
-                    """<p>Printing is not available due to a bug in PyQt5."""
-                    """Please upgrade.</p>"""))
-            return
-    
-    def __printPdfClickedFrame(self):
-        """
-        Private slot to print the selected frame to PDF.
-        """
-        printer = QPrinter(mode=QPrinter.HighResolution)
-        if Preferences.getPrinter("ColorMode"):
-            printer.setColorMode(QPrinter.Color)
-        else:
-            printer.setColorMode(QPrinter.GrayScale)
-        printerName = Preferences.getPrinter("PrinterName")
-        if printerName:
-            printer.setPrinterName(printerName)
-        printer.setOutputFormat(QPrinter.PdfFormat)
-        name = self.__clickedFrame.url().path().rsplit('/', 1)[-1]
-        if name:
-            name = name.rsplit('.', 1)[0]
-            name += '.pdf'
-            printer.setOutputFileName(name)
-        
-        printDialog = QPrintDialog(printer, self)
-        if printDialog.exec_() == QDialog.Accepted:
-            try:
-                self.__clickedFrame.print_(printer)
-            except AttributeError:
-                E5MessageBox.critical(
-                    self,
-                    self.tr("eric6 Web Browser"),
-                    self.tr(
-                        """<p>Printing is not available due to a bug in"""
-                        """ PyQt5. Please upgrade.</p>"""))
-                return
-    
-    def __zoomInClickedFrame(self):
-        """
-        Private slot to zoom into the clicked frame.
-        """
-        index = self.__levelForZoom(
-            int(self.__clickedFrame.zoomFactor() * 100))
-        if index < len(self.__zoomLevels) - 1:
-            self.__clickedFrame.setZoomFactor(
-                self.__zoomLevels[index + 1] / 100)
-    
-    def __zoomResetClickedFrame(self):
-        """
-        Private slot to reset the zoom factor of the clicked frame.
-        """
-        self.__clickedFrame.setZoomFactor(self.__currentZoom / 100)
-    
-    def __zoomOutClickedFrame(self):
-        """
-        Private slot to zoom out of the clicked frame.
-        """
-        index = self.__levelForZoom(
-            int(self.__clickedFrame.zoomFactor() * 100))
-        if index > 0:
-            self.__clickedFrame.setZoomFactor(
-                self.__zoomLevels[index - 1] / 100)
-    
-    def __showClickedFrameSource(self):
-        """
-        Private slot to show the source of the clicked frame.
-        """
-        from QScintilla.MiniEditor import MiniEditor
-        src = self.__clickedFrame.toHtml()
-        editor = MiniEditor(parent=self)
-        editor.setText(src, "Html")
-        editor.setLanguage("dummy.html")
-        editor.show()
-    
-    ###########################################################################
-    ## Speed Dial slots below
-    ###########################################################################
-    
-    def __addSpeedDial(self):
-        """
-        Private slot to add a new speed dial.
-        """
-        self.page().mainFrame().evaluateJavaScript("addSpeedDial();")
-    
-    def __configureSpeedDial(self):
-        """
-        Private slot to configure the speed dial.
-        """
-        self.page().mainFrame().evaluateJavaScript("configureSpeedDial();")
-    
-    def __reloadAllSpeedDials(self):
-        """
-        Private slot to reload all speed dials.
-        """
-        self.page().mainFrame().evaluateJavaScript("reloadAll();")
-    
-    def __resetSpeedDials(self):
-        """
-        Private slot to reset all speed dials to the default pages.
-        """
-        self.__speedDial.resetDials()
-
-
-def contentSniff(data):
-    """
-    Module function to do some content sniffing to check, if the data is HTML.
-    
-    @param data data block to sniff at (string)
-    @return flag indicating HTML content (boolean)
-    """
-    if data.contains("<!doctype") or \
-       data.contains("<script") or \
-       data.contains("<html") or \
-       data.contains("<!--") or \
-       data.contains("<head") or \
-       data.contains("<iframe") or \
-       data.contains("<h1") or \
-       data.contains("<div") or \
-       data.contains("<font") or \
-       data.contains("<table") or \
-       data.contains("<a") or \
-       data.contains("<style") or \
-       data.contains("<title") or \
-       data.contains("<b") or \
-       data.contains("<body") or \
-       data.contains("<br") or \
-       data.contains("<p"):
-        return True
-    
-    return False

eric ide

mercurial