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