src/eric7/WebBrowser/Network/EricSchemeHandler.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a scheme handler for the eric: scheme.
8 """
9
10 from PyQt6.QtCore import pyqtSignal, QBuffer, QIODevice, QUrlQuery, QMutex
11 from PyQt6.QtWebEngineCore import QWebEngineUrlSchemeHandler
12
13 from EricWidgets.EricApplication import ericApp
14
15 from EricUtilities.EricMutexLocker import EricMutexLocker
16
17 from ..Tools.WebBrowserTools import (
18 getHtmlPage, getJavascript, pixmapFileToDataUrl
19 )
20
21 _SupportedPages = [
22 "adblock", # error page for URLs blocked by AdBlock
23 "home", "start", "startpage", # eric home page
24 "speeddial", # eric speeddial
25 ]
26
27
28 class EricSchemeHandler(QWebEngineUrlSchemeHandler):
29 """
30 Class implementing a scheme handler for the eric: scheme.
31 """
32 def __init__(self, parent=None):
33 """
34 Constructor
35
36 @param parent reference to the parent object
37 @type QObject
38 """
39 super().__init__(parent)
40
41 self.__replies = []
42
43 def requestStarted(self, job):
44 """
45 Public method handling the URL request.
46
47 @param job URL request job
48 @type QWebEngineUrlRequestJob
49 """
50 reply = EricSchemeReply(job)
51 reply.closed.connect(lambda: self.__replyClosed(reply))
52 self.__replies.append(reply)
53 job.reply(b"text/html", reply)
54
55 def __replyClosed(self, reply):
56 """
57 Private slot handling the closed signal of a reply.
58
59 @param reply reference to the network reply
60 @type EricSchemeReply
61 """
62 if reply in self.__replies:
63 self.__replies.remove(reply)
64
65
66 class EricSchemeReply(QIODevice):
67 """
68 Class implementing a reply for a requested eric: page.
69
70 @signal closed emitted to signal that the web engine has read
71 the data
72 """
73 closed = pyqtSignal()
74
75 _speedDialPage = ""
76
77 def __init__(self, job, parent=None):
78 """
79 Constructor
80
81 @param job reference to the URL request
82 @type QWebEngineUrlRequestJob
83 @param parent reference to the parent object
84 @type QObject
85 """
86 super().__init__(parent)
87
88 self.__loaded = False
89 self.__job = job
90 self.__mutex = QMutex()
91
92 self.__pageName = self.__job.requestUrl().path()
93 self.__buffer = QBuffer()
94
95 self.__loadPage()
96
97 def __loadPage(self):
98 """
99 Private method to load the requested page.
100 """
101 if self.__loaded:
102 return
103
104 with EricMutexLocker(self.__mutex):
105 if self.__pageName == "adblock":
106 contents = self.__adBlockPage()
107 elif self.__pageName in ["home", "start", "startpage"]:
108 contents = self.__startPage()
109 elif self.__pageName == "speeddial":
110 contents = self.__speedDialPage()
111 else:
112 contents = self.__errorPage()
113
114 self.__buffer.setData(contents.encode("utf-8"))
115 self.__buffer.open(QIODevice.OpenModeFlag.ReadOnly)
116 self.open(QIODevice.OpenModeFlag.ReadOnly)
117
118 self.readyRead.emit()
119
120 self.__loaded = True
121
122 def bytesAvailable(self):
123 """
124 Public method to get the number of available bytes.
125
126 @return number of available bytes
127 @rtype int
128 """
129 with EricMutexLocker(self.__mutex):
130 return self.__buffer.bytesAvailable()
131
132 def readData(self, maxlen):
133 """
134 Public method to retrieve data from the reply object.
135
136 @param maxlen maximum number of bytes to read (integer)
137 @return string containing the data (bytes)
138 """
139 with EricMutexLocker(self.__mutex):
140 return self.__buffer.read(maxlen)
141
142 def close(self):
143 """
144 Public method used to cloase the reply.
145 """
146 super().close()
147 self.closed.emit()
148
149 def __adBlockPage(self):
150 """
151 Private method to build the AdBlock page.
152
153 @return built AdBlock page
154 @rtype str
155 """
156 query = QUrlQuery(self.__job.requestUrl())
157 rule = query.queryItemValue("rule")
158 subscription = query.queryItemValue("subscription")
159 title = self.tr("Content blocked by AdBlock Plus")
160 message = self.tr(
161 "Blocked by rule: <i>{0} ({1})</i>").format(rule, subscription)
162
163 page = getHtmlPage("adblockPage.html")
164 page = page.replace(
165 "@FAVICON@", pixmapFileToDataUrl("adBlockPlus16.png", True))
166 page = page.replace(
167 "@IMAGE@", pixmapFileToDataUrl("adBlockPlus64.png", True))
168 page = page.replace("@TITLE@", title)
169 page = page.replace("@MESSAGE@", message)
170
171 return page
172
173 def __errorPage(self):
174 """
175 Private method to build the Error page.
176
177 @return built Error page
178 @rtype str
179 """
180 page = getHtmlPage("ericErrorPage.html")
181 page = page.replace(
182 "@FAVICON@", pixmapFileToDataUrl("ericWeb16.png", True))
183 page = page.replace(
184 "@IMAGE@", pixmapFileToDataUrl("ericWeb32.png", True))
185 page = page.replace(
186 "@TITLE@", self.tr("Error accessing eric: URL"))
187 page = page.replace(
188 "@MESSAGE@", self.tr(
189 "The special URL <strong>{0}</strong> is not supported."
190 " Please use one of these."
191 ).format(self.__job.requestUrl().toDisplayString())
192 )
193 page = page.replace(
194 "@ERICLIST@", "<br/>".join([
195 '<a href="eric:{0}">{0}</a>'.format(u)
196 for u in sorted(_SupportedPages)
197 ])
198 )
199
200 return page
201
202 def __startPage(self):
203 """
204 Private method to build the Start page.
205
206 @return built Start page
207 @rtype str
208 """
209 page = getHtmlPage("startPage.html")
210 page = page.replace(
211 "@FAVICON@", pixmapFileToDataUrl("ericWeb16.png", True))
212 page = page.replace(
213 "@IMAGE@", pixmapFileToDataUrl("ericWeb32.png", True))
214 page = page.replace(
215 "@TITLE@", self.tr("Welcome to eric Web Browser!"))
216 page = page.replace("@ERIC_LINK@", self.tr("About eric"))
217 page = page.replace("@HEADER_TITLE@", self.tr("eric Web Browser"))
218 page = page.replace("@SUBMIT@", self.tr("Search!"))
219 ltr = "LTR" if ericApp().isLeftToRight() else"RTL"
220 page = page.replace("@QT_LAYOUT_DIRECTION@", ltr)
221
222 return page
223
224 def __speedDialPage(self):
225 """
226 Private method to create the Speeddial page.
227
228 @return prepared speeddial page
229 @rtype str
230 """
231 if not self._speedDialPage:
232 page = getHtmlPage("speeddialPage.html")
233 page = page.replace(
234 "@FAVICON@", pixmapFileToDataUrl("ericWeb16.png", True))
235 page = page.replace(
236 "@IMG_PLUS@", pixmapFileToDataUrl("plus.png", True))
237 page = page.replace(
238 "@IMG_CLOSE@", pixmapFileToDataUrl("close.png", True))
239 page = page.replace(
240 "@IMG_EDIT@", pixmapFileToDataUrl("edit.png", True))
241 page = page.replace(
242 "@IMG_RELOAD@", pixmapFileToDataUrl("reload.png", True))
243 page = page.replace(
244 "@IMG_SETTINGS@", pixmapFileToDataUrl("setting.png", True))
245 page = page.replace(
246 "@LOADING-IMG@", pixmapFileToDataUrl("loading.gif", True))
247 page = page.replace(
248 "@BOX-BORDER@",
249 pixmapFileToDataUrl("box-border-small.png", True))
250
251 page = page.replace("@JQUERY@", getJavascript("jquery.js"))
252 page = page.replace("@JQUERY-UI@", getJavascript("jquery-ui.js"))
253
254 page = page.replace("@SITE-TITLE@", self.tr("Speed Dial"))
255 page = page.replace("@URL@", self.tr("URL"))
256 page = page.replace("@TITLE@", self.tr("Title"))
257 page = page.replace("@APPLY@", self.tr("Apply"))
258 page = page.replace("@CLOSE@", self.tr("Close"))
259 page = page.replace("@NEW-PAGE@", self.tr("New Page"))
260 page = page.replace("@TITLE-EDIT@", self.tr("Edit"))
261 page = page.replace("@TITLE-REMOVE@", self.tr("Remove"))
262 page = page.replace("@TITLE-RELOAD@", self.tr("Reload"))
263 page = page.replace("@TITLE-WARN@",
264 self.tr("Are you sure to remove this"
265 " speed dial?"))
266 page = page.replace("@TITLE-WARN-REL@",
267 self.tr("Are you sure you want to reload"
268 " all speed dials?"))
269 page = page.replace("@TITLE-FETCHTITLE@",
270 self.tr("Load title from page"))
271 page = page.replace("@SETTINGS-TITLE@",
272 self.tr("Speed Dial Settings"))
273 page = page.replace("@ADD-TITLE@", self.tr("Add New Page"))
274 page = page.replace("@TXT_NRROWS@",
275 self.tr("Maximum pages in a row:"))
276 page = page.replace("@TXT_SDSIZE@",
277 self.tr("Change size of pages:"))
278 page = page.replace("@JAVASCRIPT_DISABLED@",
279 self.tr("SpeedDial requires enabled"
280 " JavaScript."))
281
282 self._speedDialPage = page
283
284 from WebBrowser.WebBrowserWindow import WebBrowserWindow
285 dial = WebBrowserWindow.speedDial()
286 page = (
287 self._speedDialPage
288 .replace("@INITIAL-SCRIPT@", dial.initialScript())
289 .replace("@ROW-PAGES@", str(dial.pagesInRow()))
290 .replace("@SD-SIZE@", str(dial.sdSize()))
291 )
292
293 return page

eric ide

mercurial