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