Fri, 01 Feb 2019 19:18:45 +0100
EricSchemeHandler: ensure that the page is loaded immediately.
# -*- coding: utf-8 -*- # Copyright (c) 2016 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a scheme handler for the eric: scheme. """ from __future__ import unicode_literals from PyQt5.QtCore import pyqtSignal, QByteArray, QBuffer, QIODevice, \ QUrlQuery, QMutex, QMutexLocker from PyQt5.QtWidgets import qApp from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler from ..Tools.WebBrowserTools import readAllFileContents class EricSchemeHandler(QWebEngineUrlSchemeHandler): """ Class implementing a scheme handler for the eric: scheme. """ SupportedPages = [ "adblock", # error page for URLs blocked by AdBlock "home", "start", "startpage", # eric home page "speeddial", # eric speeddial ] def __init__(self, parent=None): """ Constructor @param parent reference to the parent object @type QObject """ super(EricSchemeHandler, self).__init__(parent) self.__replies = [] def requestStarted(self, job): """ Public method handling the URL request. @param job URL request job @type QWebEngineUrlRequestJob """ if job.requestUrl().path() in self.SupportedPages: reply = EricSchemeReply(job) reply.closed.connect(lambda: self.__replyClosed(reply)) self.__replies.append(reply) job.reply(b"text/html", reply) else: job.reply(QByteArray(), QBuffer()) # job.fail(QWebEngineUrlRequestJob.UrlNotFound) def __replyClosed(self, reply): """ Private slot handling the closed signal of a reply. @param reply reference to the network reply @type EricSchemeReply """ if reply in self.__replies: self.__replies.remove(reply) class EricSchemeReply(QIODevice): """ Class implementing a reply for a requested eric: page. @signal closed emitted to signal that the web engine has read the data """ closed = pyqtSignal() _speedDialPage = "" def __init__(self, job, parent=None): """ Constructor @param job reference to the URL request @type QWebEngineUrlRequestJob @param parent reference to the parent object @type QObject """ super(EricSchemeReply, self).__init__(parent) self.__loaded = False self.__job = job self.__mutex = QMutex() self.__pageName = self.__job.requestUrl().path() self.__buffer = QBuffer() self.__loadPage() def __loadPage(self): """ Private method to load the requested page. """ if self.__loaded: return lock = QMutexLocker(self.__mutex) if self.__pageName == "adblock": contents = self.__adBlockPage() elif self.__pageName in ["home", "start", "startpage"]: contents = self.__startPage() elif self.__pageName == "speeddial": contents = self.__speedDialPage() else: contents = "" self.__buffer.setData(contents.encode("utf-8")) self.__buffer.open(QIODevice.ReadOnly) self.open(QIODevice.ReadOnly) lock.unlock() self.readyRead.emit() self.__loaded = True def bytesAvailable(self): """ Public method to get the number of available bytes. @return number of available bytes @rtype int """ lock = QMutexLocker(self.__mutex) # __IGNORE_WARNING__ return self.__buffer.bytesAvailable() def readData(self, maxlen): """ Public method to retrieve data from the reply object. @param maxlen maximum number of bytes to read (integer) @return string containing the data (bytes) """ lock = QMutexLocker(self.__mutex) # __IGNORE_WARNING__ return self.__buffer.read(maxlen) def close(self): """ Public method used to cloase the reply. """ super(EricSchemeReply, self).close() self.closed.emit() def __adBlockPage(self): """ Private method to build the AdBlock page. @return built AdBlock page @rtype str """ query = QUrlQuery(self.__job.requestUrl()) rule = query.queryItemValue("rule") subscription = query.queryItemValue("subscription") title = self.tr("Content blocked by AdBlock Plus") message = self.tr( "Blocked by rule: <i>{0} ({1})</i>").format(rule, subscription) page = readAllFileContents(":/html/adblockPage.html") page = page.replace( "@FAVICON@", "qrc:icons/adBlockPlus16.png") page = page.replace( "@IMAGE@", "qrc:icons/adBlockPlus64.png") page = page.replace("@TITLE@", title) page = page.replace("@MESSAGE@", message) return page def __startPage(self): """ Private method to build the Start page. @return built Start page @rtype str """ page = readAllFileContents(":/html/startPage.html") page = page.replace("@FAVICON@", "qrc:icons/ericWeb16.png") page = page.replace("@IMAGE@", "qrc:icons/ericWeb32.png") page = page.replace("@TITLE@", self.tr("Welcome to eric6 Web Browser!")) page = page.replace("@ERIC_LINK@", self.tr("About eric6")) page = page.replace("@HEADER_TITLE@", self.tr("eric6 Web Browser")) page = page.replace("@SUBMIT@", self.tr("Search!")) if qApp.isLeftToRight(): ltr = "LTR" else: ltr = "RTL" page = page.replace("@QT_LAYOUT_DIRECTION@", ltr) return page def __speedDialPage(self): """ Private method to create the Speeddial page. @return prepared speeddial page (QByteArray) """ if not self._speedDialPage: page = readAllFileContents(":/html/speeddialPage.html") page = page.replace("@FAVICON@", "qrc:icons/ericWeb16.png") page = page.replace("@IMG_PLUS@", "qrc:icons/plus.png") page = page.replace("@IMG_CLOSE@", "qrc:icons/close.png") page = page.replace("@IMG_EDIT@", "qrc:icons/edit.png") page = page.replace("@IMG_RELOAD@", "qrc:icons/reload.png") page = page.replace("@IMG_SETTINGS@", "qrc:icons/setting.png") page = page.replace("@LOADING-IMG@", "qrc:icons/loading.gif") page = page.replace("@BOX-BORDER@", "qrc:icons/box-border-small.png") page = page.replace("@JQUERY@", "qrc:javascript/jquery.js") page = page.replace("@JQUERY-UI@", "qrc:javascript/jquery-ui.js") page = page.replace("@SITE-TITLE@", self.tr("Speed Dial")) page = page.replace("@URL@", self.tr("URL")) page = page.replace("@TITLE@", self.tr("Title")) page = page.replace("@APPLY@", self.tr("Apply")) page = page.replace("@CLOSE@", self.tr("Close")) page = page.replace("@NEW-PAGE@", self.tr("New Page")) page = page.replace("@TITLE-EDIT@", self.tr("Edit")) page = page.replace("@TITLE-REMOVE@", self.tr("Remove")) page = page.replace("@TITLE-RELOAD@", self.tr("Reload")) page = page.replace("@TITLE-WARN@", self.tr("Are you sure to remove this" " speed dial?")) page = page.replace("@TITLE-WARN-REL@", self.tr("Are you sure you want to reload" " all speed dials?")) page = page.replace("@TITLE-FETCHTITLE@", self.tr("Load title from page")) page = page.replace("@SETTINGS-TITLE@", self.tr("Speed Dial Settings")) page = page.replace("@ADD-TITLE@", self.tr("Add New Page")) page = page.replace("@TXT_NRROWS@", self.tr("Maximum pages in a row:")) page = page.replace("@TXT_SDSIZE@", self.tr("Change size of pages:")) page = page.replace("@JAVASCRIPT_DISABLED@", self.tr("SpeedDial requires enabled" " JavaScript.")) self._speedDialPage = page from WebBrowser.WebBrowserWindow import WebBrowserWindow dial = WebBrowserWindow.speedDial() page = ( self._speedDialPage .replace("@INITIAL-SCRIPT@", dial.initialScript()) .replace("@ROW-PAGES@", str(dial.pagesInRow())) .replace("@SD-SIZE@", str(dial.sdSize())) ) return page