Helpviewer/HelpBrowserWV.py

changeset 0
de9c2efb9d02
child 7
c679fb30c8f3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Helpviewer/HelpBrowserWV.py	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,941 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2008 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+
+"""
+Module implementing the helpbrowser using QWebView.
+"""
+
+import os
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from PyQt4.QtWebKit import QWebView, QWebPage, QWebSettings
+from PyQt4.QtNetwork import QNetworkProxy, QNetworkAccessManager, QNetworkReply, \
+    QNetworkRequest
+
+import Preferences
+import Utilities
+import UI.PixmapCache
+
+from DownloadDialog import DownloadDialog
+from HelpWebSearchWidget import HelpWebSearchWidget
+from Bookmarks.AddBookmarkDialog import AddBookmarkDialog
+from JavaScriptResources import fetchLinks_js
+from HTMLResources import notFoundPage_html
+import Helpviewer.HelpWindow
+
+from Network.NetworkAccessManagerProxy import NetworkAccessManagerProxy
+
+from OpenSearch.OpenSearchEngineAction import OpenSearchEngineAction
+
+##########################################################################################
+
+class JavaScriptExternalObject(QObject):
+    """
+    Class implementing an external javascript object to add search providers.
+    """
+    @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)
+        """
+        HelpWebSearchWidget.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 Eric Web Browser!"), 
+        QT_TRANSLATE_NOOP("JavaScriptEricObject", "Eric Web Browser"), 
+        QT_TRANSLATE_NOOP("JavaScriptEricObject", "Search!"), 
+        QT_TRANSLATE_NOOP("JavaScriptEricObject", "About Eric"), 
+    ]
+    
+    @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.trUtf8(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.trUtf8("Search results provided by {0}")\
+            .format(HelpWebSearchWidget.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 unicode(
+            HelpWebSearchWidget.openSearchManager().currentEngine()\
+            .searchUrl(searchStr).toEncoded())
+
+##########################################################################################
+
+class HelpWebPage(QWebPage):
+    """
+    Class implementing an enhanced web page.
+    """
+    def __init__(self, parent = None):
+        """
+        Constructor
+        
+        @param parent parent widget of this window (QWidget)
+        """
+        QWebPage.__init__(self, parent)
+        
+        self.__lastRequest = None
+        self.__lastRequestType = QWebPage.NavigationTypeOther
+        
+        self.__proxy = NetworkAccessManagerProxy(self)
+        self.__proxy.setWebPage(self)
+        self.__proxy.setPrimaryNetworkAccessManager(
+            Helpviewer.HelpWindow.HelpWindow.networkAccessManager())
+        self.setNetworkAccessManager(self.__proxy)
+    
+    def acceptNavigationRequest(self, frame, request, type_):
+        """
+        Protected 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
+        self.__lastRequestType = type_
+        
+        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)
+        """
+        request.setAttribute(QNetworkRequest.User + 100, QVariant(self))
+        request.setAttribute(QNetworkRequest.User + 101, 
+                             QVariant(self.__lastRequestType))
+    
+    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
+
+##########################################################################################
+
+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(const 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(const QString&) emitted, when the mouse hovers over a link
+    @signal search(const QUrl &) emitted, when a search is requested
+    """
+    def __init__(self, parent = None, name = ""):
+        """
+        Constructor
+        
+        @param parent parent widget of this window (QWidget)
+        @param name name of this window (string)
+        """
+        QWebView.__init__(self, parent)
+        self.setObjectName(name)
+        self.setWhatsThis(self.trUtf8(
+                """<b>Help Window</b>"""
+                """<p>This window displays the selected help information.</p>"""
+        ))
+        
+        self.__page = HelpWebPage(self)
+        self.setPage(self.__page)
+        
+        self.mw = parent
+        self.ctrlPressed = False
+        self.__downloadWindows = []
+        self.__isLoading = False
+        
+        self.__currentZoom = 100
+        self.__zoomLevels = [
+            30, 50, 67, 80, 90, 
+            100, 
+            110, 120, 133, 150, 170, 200, 240, 300, 
+        ]
+        
+        self.__javaScriptBinding = None
+        self.__javaScriptEricObject = None
+        
+        self.connect(self.mw, SIGNAL("zoomTextOnlyChanged(bool)"), self.__applyZoom)
+        
+        self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
+        self.connect(self, SIGNAL('linkClicked(const QUrl &)'), self.setSource)
+        self.connect(self, SIGNAL('iconChanged()'), self.__iconChanged)
+        
+        self.connect(self, SIGNAL('urlChanged(const QUrl &)'), self.__urlChanged)
+        self.connect(self, SIGNAL('statusBarMessage(const QString &)'), 
+            self.__statusBarMessage)
+        self.connect(self.page(), 
+            SIGNAL('linkHovered(const QString &, const QString &, const QString &)'), 
+            self.__linkHovered)
+        
+        self.connect(self, SIGNAL('loadStarted()'), self.__loadStarted)
+        self.connect(self, SIGNAL('loadProgress(int)'), self.__loadProgress)
+        self.connect(self, SIGNAL('loadFinished(bool)'), self.__loadFinished)
+        
+        self.page().setForwardUnsupportedContent(True)
+        self.connect(self.page(), SIGNAL('unsupportedContent(QNetworkReply *)'), 
+            self.__unsupportedContent)
+        
+        self.connect(self.page(), SIGNAL('downloadRequested(const QNetworkRequest &)'), 
+            self.__downloadRequested)
+        self.connect(self.page(), SIGNAL("frameCreated(QWebFrame *)"), 
+            self.__addExternalBinding)
+        self.__addExternalBinding(self.page().mainFrame())
+        
+        self.connect(HelpWebSearchWidget.openSearchManager(), 
+                     SIGNAL("currentEngineChanged()"), 
+                     self.__currentEngineChanged)
+    
+    def __addExternalBinding(self, frame = None):
+        """
+        Private slot to add javascript bindings for adding search providers.
+        
+        @param frame reference to the web frame (QWebFrame)
+        """
+        self.page().settings().setAttribute(QWebSettings.JavascriptEnabled, True)
+        if self.__javaScriptBinding is None:
+            self.__javaScriptBinding = JavaScriptExternalObject(self)
+        
+        if frame is None:
+            # called from QWebFrame.javaScriptWindowObjectCleared
+            frame = self.sender()
+            if frame.url().scheme() == "pyrc" and frame.url().path() == "home":
+                if self.__javaScriptEricObject is None:
+                    self.__javaScriptEricObject = JavaScriptEricObject(self)
+                frame.addToJavaScriptWindowObject("eric", self.__javaScriptEricObject)
+        else:
+            # called from QWebPage.frameCreated
+            self.connect(frame, SIGNAL("javaScriptWindowObjectCleared()"), 
+                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 = []
+        
+        lst = self.page().mainFrame().evaluateJavaScript(fetchLinks_js).toList()
+        for variant in lst:
+            m = variant.toMap()
+            rel = m["rel"].toString()
+            type_ = m["type"].toString()
+            href = m["href"].toString()
+            title =  m["title"].toString()
+            
+            if href == "" or type_ == "":
+                continue
+            if relation and rel != relation:
+                continue
+            
+            resource = LinkedResource()
+            resource.rel = rel
+            resource.type_ = type_
+            resource.href = href
+            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() == "pyrc:home":
+            self.reload()
+    
+    def setSource(self, name):
+        """
+        Public method used to set the source to be displayed.
+        
+        @param name filename to be shown (QUrl)
+        """
+        if name is None or not name.isValid():
+            return
+        
+        if self.ctrlPressed:
+            # open in a new window
+            self.mw.newTab(name)
+            self.ctrlPressed = False
+            return
+        
+        if not name.scheme():
+            name.setUrl(Preferences.getHelp("DefaultScheme") + 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():
+                QMessageBox.critical(None,
+                    self.trUtf8("Web Browser"),
+                    self.trUtf8("""<p>The file <b>{0}</b> does not exist.</p>""")\
+                        .format(name.toLocalFile()),
+                    QMessageBox.StandardButtons(\
+                        QMessageBox.Ok))
+                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:
+                    QMessageBox.critical(self,
+                        self.trUtf8("Web Browser"),
+                        self.trUtf8("""<p>Could not start a viewer"""
+                        """ for file <b>{0}</b>.</p>""").format(name.path()))
+                return
+        elif name.scheme() in ["mailto", "ftp"]:
+            started = QDesktopServices.openUrl(name)
+            if not started:
+                QMessageBox.critical(self,
+                    self.trUtf8("Web Browser"),
+                    self.trUtf8("""<p>Could not start an application"""
+                    """ for URL <b>{0}</b>.</p>""").format(name.toString()))
+            return
+        elif name.scheme() == "javascript":
+            scriptSource = name.toString()[11:]
+            res = self.page().mainFrame().evaluateJavaScript(scriptSource).toString()
+            if res:
+                self.setHtml(res)
+            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:
+                    QMessageBox.critical(self,
+                        self.trUtf8("Web Browser"),
+                        self.trUtf8("""<p>Could not start a viewer"""
+                        """ for file <b>{0}</b>.</p>""").format(name.path()))
+                return
+        
+        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.
+        """
+        try:
+            self.setZoomFactor(self.__currentZoom / 100.0)
+        except AttributeError:
+            self.setTextSizeMultiplier(self.__currentZoom / 100.0)
+    
+    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.
+        """
+        self.__currentZoom = 100
+        self.__applyZoom()
+    
+    def wheelEvent(self, evt):
+        """
+        Protected method to handle wheel events.
+        
+        @param evt reference to the wheel event (QWheelEvent)
+        """
+        if evt.modifiers() & Qt.ControlModifier:
+            degrees = evt.delta() / 8
+            steps = degrees / 15
+            self.__currentZoom += steps * 10
+            self.__applyZoom()
+            evt.accept()
+            return
+        
+        QWebView.wheelEvent(self, evt)
+    
+    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):
+        """
+        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)
+        """
+        findFlags = QWebPage.FindFlags()
+        if case:
+            findFlags |= QWebPage.FindCaseSensitively
+        if backwards:
+            findFlags |= QWebPage.FindBackward
+        if wrap:
+            findFlags |= QWebPage.FindWrapsAroundDocument
+        
+        return self.findText(txt, findFlags)
+    
+    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)
+        """
+        pos = evt.pos()
+        menu = QMenu(self)
+        
+        hit = self.page().mainFrame().hitTestContent(evt.pos())
+        if not hit.linkUrl().isEmpty():
+            act = menu.addAction(self.trUtf8("Open Link in New Tab\tCtrl+LMB"),
+                self.__openLinkInNewTab)
+            act.setData(QVariant(hit.linkUrl()))
+            menu.addSeparator()
+            menu.addAction(self.trUtf8("Save Lin&k"), self.__downloadLink)
+            act = menu.addAction(self.trUtf8("Bookmark this Link"), self.__bookmarkLink)
+            act.setData(QVariant(hit.linkUrl()))
+            menu.addSeparator()
+            menu.addAction(self.trUtf8("Copy Link to Clipboard"), self.__copyLink)
+        
+        if not hit.imageUrl().isEmpty():
+            if not menu.isEmpty():
+                menu.addSeparator()
+            act = menu.addAction(self.trUtf8("Open Image in New Tab"), 
+                self.__openLinkInNewTab)
+            act.setData(QVariant(hit.imageUrl()))
+            menu.addSeparator()
+            menu.addAction(self.trUtf8("Save Image"), self.__downloadImage)
+            menu.addAction(self.trUtf8("Copy Image to Clipboard"), self.__copyImage)
+            act = menu.addAction(self.trUtf8("Copy Image Location to Clipboard"), 
+                self.__copyImageLocation)
+            act.setData(QVariant(hit.imageUrl().toString()))
+            menu.addSeparator()
+            act = menu.addAction(self.trUtf8("Block Image"), self.__blockImage)
+            act.setData(QVariant(hit.imageUrl().toString()))
+        
+        if not menu.isEmpty():
+            menu.addSeparator()
+        menu.addAction(self.mw.newTabAct)
+        menu.addAction(self.mw.newAct)
+        menu.addSeparator()
+        menu.addAction(self.mw.saveAsAct)
+        menu.addSeparator()
+        menu.addAction(self.trUtf8("Bookmark this Page"), self.__addBookmark)
+        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.zoomOutAct)
+        menu.addSeparator()
+        if self.selectedText():
+            menu.addAction(self.mw.copyAct)
+        menu.addAction(self.mw.findAct)
+        menu.addSeparator()
+        if self.selectedText():
+            self.__searchMenu = menu.addMenu(self.trUtf8("Search with..."))
+            
+            engineNames = HelpWebSearchWidget.openSearchManager().allEnginesNames()
+            for engineName in engineNames:
+                engine = HelpWebSearchWidget.openSearchManager().engine(engineName)
+                act = OpenSearchEngineAction(engine, self.__searchMenu)
+                self.__searchMenu.addAction(act)
+                act.setData(QVariant(engineName))
+            self.connect(self.__searchMenu, SIGNAL("triggered(QAction *)"), 
+                         self.__searchRequested)
+            
+            menu.addSeparator()
+        menu.addAction(self.trUtf8("Web Inspector..."), self.__webInspector)
+        
+        menu.exec_(evt.globalPos())
+    
+    def __openLinkInNewTab(self):
+        """
+        Private method called by the context menu to open a link in a new window.
+        """
+        act = self.sender()
+        url = act.data().toUrl()
+        if url.isEmpty():
+            return
+        
+        oldCtrlPressed = self.ctrlPressed
+        self.ctrlPressed = True
+        self.setSource(url)
+        self.ctrlPressed = oldCtrlPressed
+    
+    def __bookmarkLink(self):
+        """
+        Private slot to bookmark a link via the context menu.
+        """
+        act = self.sender()
+        url = act.data().toUrl()
+        if url.isEmpty():
+            return
+        
+        dlg = AddBookmarkDialog()
+        dlg.setUrl(unicode(url.toEncoded()))
+        dlg.exec_()
+    
+    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 __copyImageLocation(self):
+        """
+        Private slot to copy an image location to the clipboard.
+        """
+        act = self.sender()
+        url = act.data().toString()
+        QApplication.clipboard().setText(url)
+    
+    def __blockImage(self):
+        """
+        Private slot to add a block rule for an image URL.
+        """
+        act = self.sender()
+        url = act.data().toString()
+        dlg = Helpviewer.HelpWindow.HelpWindow.adblockManager().showDialog()
+        dlg.addCustomRule(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().toString()
+        if engineName:
+            engine = HelpWebSearchWidget.openSearchManager().engine(engineName)
+            self.emit(SIGNAL("search(const QUrl &)"), engine.searchUrl(searchText))
+    
+    def __webInspector(self):
+        """
+        Private slot to show the web inspector window.
+        """
+        self.triggerPageAction(QWebPage.InspectElement)
+    
+    def __addBookmark(self):
+        """
+        Private slot to bookmark the current link.
+        """
+        dlg = AddBookmarkDialog()
+        dlg.setUrl(unicode(self.url().toEncoded()))
+        dlg.setTitle(self.title())
+        dlg.exec_()
+    
+    def keyPressEvent(self, evt):
+        """
+        Protected method called by a key press.
+        
+        This method is overridden from QTextBrowser.
+        
+        @param evt the key event (QKeyEvent)
+        """
+        self.ctrlPressed = (evt.key() == Qt.Key_Control)
+        QWebView.keyPressEvent(self, evt)
+    
+    def keyReleaseEvent(self, evt):
+        """
+        Protected method called by a key release.
+        
+        This method is overridden from QTextBrowser.
+        
+        @param evt the key event (QKeyEvent)
+        """
+        self.ctrlPressed = False
+        QWebView.keyReleaseEvent(self, evt)
+    
+    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.emit(SIGNAL('sourceChanged(const QUrl &)'), url)
+        
+        self.emit(SIGNAL('forwardAvailable(bool)'), self.isForwardAvailable())
+        self.emit(SIGNAL('backwardAvailable(bool)'), 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.emit(SIGNAL('highlighted(const QString&)'), link)
+    
+    ############################################################################
+    ## Signal handlers below
+    ############################################################################
+    
+    def __loadStarted(self):
+        """
+        Private method to handle the loadStarted signal.
+        """
+        self.__isLoading = True
+        self.mw.setLoading(self)
+        self.mw.progressBar().show()
+    
+    def __loadProgress(self, progress):
+        """
+        Private method to handle the loadProgress signal.
+        
+        @param progress progress value (integer)
+        """
+        self.mw.progressBar().setValue(progress)
+    
+    def __loadFinished(self, ok):
+        """
+        Private method to handle the loadFinished signal.
+        
+        @param ok flag indicating the result (boolean)
+        """
+        self.__isLoading = False
+        self.mw.progressBar().hide()
+        self.mw.resetLoading(self)
+        
+        self.__iconChanged()
+        
+        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 saveAs(self):
+        """
+        Public method to save the current page to a file.
+        """
+        url = self.url()
+        if url.isEmpty():
+            return
+        
+        req = QNetworkRequest(url)
+        reply = self.mw.networkAccessManager().get(req)
+        self.__unsupportedContent(reply, True)
+    
+    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.url().isEmpty():
+                return
+            header = reply.header(QNetworkRequest.ContentLengthHeader)
+            size, ok = header.toInt()
+            if ok and size == 0:
+                return
+            
+            if requestFilename is None:
+                requestFilename = Preferences.getUI("RequestDownloadFilename")
+            dlg = DownloadDialog(reply, requestFilename, self.page(), download)
+            self.connect(dlg, SIGNAL("done()"), self.__downloadDone)
+            self.__downloadWindows.append(dlg)
+            dlg.show()
+        else:
+            replyUrl = reply.url()
+            if replyUrl.isEmpty():
+                return
+            
+            html = notFoundPage_html
+            urlString = unicode(replyUrl.toEncoded())
+            title = self.trUtf8("Error loading page: {0}").format(urlString)
+            pixmap = qApp.style()\
+                     .standardIcon(QStyle.SP_MessageBoxWarning, None, self)\
+                     .pixmap(32, 32)
+            imageBuffer = QBuffer()
+            imageBuffer.open(QIODevice.ReadWrite)
+            if pixmap.save(imageBuffer, "PNG"):
+                html.replace("IMAGE_BINARY_DATA_HERE", 
+                             unicode(imageBuffer.buffer().toBase64()))
+            html = html.format(
+                title, 
+                reply.errorString(), 
+                self.trUtf8("When connecting to: {0}.").format(urlString), 
+                self.trUtf8("Check the address for errors such as <b>ww</b>.example.org "
+                            "instead of <b>www</b>.example.org"), 
+                self.trUtf8("If the address is correct, try checking the network "
+                            "connection."), 
+                self.trUtf8("If your computer or network is protected by a firewall or "
+                            "proxy, make sure that the browser is permitted to access "
+                            "the network.")
+            )
+            self.setHtml(html, replyUrl)
+            self.mw.historyManager().removeHistoryEntry(replyUrl, self.title())
+            self.emit(SIGNAL('loadFinished(bool)'), False)
+    
+    def __downloadDone(self):
+        """
+        Private slot to handle the done signal of the download dialogs.
+        """
+        dlg = self.sender()
+        if dlg in self.__downloadWindows:
+            self.disconnect(dlg, SIGNAL("done()"), self.__downloadDone)
+            self.__downloadWindows.remove(dlg)
+            dlg.deleteLater()
+    
+    def __downloadRequested(self, request):
+        """
+        Private slot to handle a download request.
+        
+        @param request reference to the request object (QNetworkRequest)
+        """
+        if request.url().isEmpty():
+            return
+        mgr = self.page().networkAccessManager()
+        self.__unsupportedContent(mgr.get(request), download = True)
+    
+    def __iconChanged(self):
+        """
+        Private slot to handle the icon change.
+        """
+        self.mw.iconChanged(self.icon())
+    
+    ############################################################################
+    ## Miscellaneous methods below
+    ############################################################################
+    
+    def createWindow(self, windowType):
+        """
+        Protected method called, when a new window should be created.
+        
+        @param windowType type of the requested window (QWebPage.WebWindowType)
+        """
+        self.mw.newTab()
+        return self.mw.currentBrowser()
+    
+    def preferencesChanged(self):
+        """
+        Public method to indicate a change of the settings.
+        """
+        self.reload()

eric ide

mercurial