9 |
9 |
10 import re |
10 import re |
11 import json |
11 import json |
12 |
12 |
13 from PyQt6.QtCore import ( |
13 from PyQt6.QtCore import ( |
14 pyqtSignal, pyqtSlot, QLocale, QUrl, QUrlQuery, QByteArray, QBuffer, |
14 pyqtSignal, |
15 QIODevice, QObject |
15 pyqtSlot, |
|
16 QLocale, |
|
17 QUrl, |
|
18 QUrlQuery, |
|
19 QByteArray, |
|
20 QBuffer, |
|
21 QIODevice, |
|
22 QObject, |
16 ) |
23 ) |
17 from PyQt6.QtGui import QImage |
24 from PyQt6.QtGui import QImage |
18 from PyQt6.QtNetwork import ( |
25 from PyQt6.QtNetwork import QNetworkRequest, QNetworkAccessManager, QNetworkReply |
19 QNetworkRequest, QNetworkAccessManager, QNetworkReply |
|
20 ) |
|
21 |
26 |
22 from UI.Info import Program |
27 from UI.Info import Program |
23 |
28 |
24 import Preferences |
29 import Preferences |
25 import Utilities |
30 import Utilities |
26 |
31 |
27 |
32 |
28 class OpenSearchEngine(QObject): |
33 class OpenSearchEngine(QObject): |
29 """ |
34 """ |
30 Class implementing the open search engine. |
35 Class implementing the open search engine. |
31 |
36 |
32 @signal imageChanged() emitted after the icon has been changed |
37 @signal imageChanged() emitted after the icon has been changed |
33 @signal suggestions(list of strings) emitted after the suggestions have |
38 @signal suggestions(list of strings) emitted after the suggestions have |
34 been received |
39 been received |
35 """ |
40 """ |
|
41 |
36 imageChanged = pyqtSignal() |
42 imageChanged = pyqtSignal() |
37 suggestions = pyqtSignal(list) |
43 suggestions = pyqtSignal(list) |
38 |
44 |
39 def __init__(self, parent=None): |
45 def __init__(self, parent=None): |
40 """ |
46 """ |
41 Constructor |
47 Constructor |
42 |
48 |
43 @param parent reference to the parent object (QObject) |
49 @param parent reference to the parent object (QObject) |
44 """ |
50 """ |
45 super().__init__(parent) |
51 super().__init__(parent) |
46 |
52 |
47 self.__suggestionsReply = None |
53 self.__suggestionsReply = None |
48 self.__networkAccessManager = None |
54 self.__networkAccessManager = None |
49 self._name = "" |
55 self._name = "" |
50 self._description = "" |
56 self._description = "" |
51 self._searchUrlTemplate = "" |
57 self._searchUrlTemplate = "" |
52 self._suggestionsUrlTemplate = "" |
58 self._suggestionsUrlTemplate = "" |
53 self._searchParameters = [] # list of two tuples |
59 self._searchParameters = [] # list of two tuples |
54 self._suggestionsParameters = [] # list of two tuples |
60 self._suggestionsParameters = [] # list of two tuples |
55 self._imageUrl = "" |
61 self._imageUrl = "" |
56 self.__image = QImage() |
62 self.__image = QImage() |
57 self.__iconMoved = False |
63 self.__iconMoved = False |
58 self.__searchMethod = "get" |
64 self.__searchMethod = "get" |
59 self.__suggestionsMethod = "get" |
65 self.__suggestionsMethod = "get" |
60 self.__requestMethods = { |
66 self.__requestMethods = { |
61 "get": QNetworkAccessManager.Operation.GetOperation, |
67 "get": QNetworkAccessManager.Operation.GetOperation, |
62 "post": QNetworkAccessManager.Operation.PostOperation, |
68 "post": QNetworkAccessManager.Operation.PostOperation, |
63 } |
69 } |
64 |
70 |
65 self.__replies = [] |
71 self.__replies = [] |
66 |
72 |
67 @classmethod |
73 @classmethod |
68 def parseTemplate(cls, searchTerm, searchTemplate): |
74 def parseTemplate(cls, searchTerm, searchTemplate): |
69 """ |
75 """ |
70 Class method to parse a search template. |
76 Class method to parse a search template. |
71 |
77 |
72 @param searchTerm term to search for (string) |
78 @param searchTerm term to search for (string) |
73 @param searchTemplate template to be parsed (string) |
79 @param searchTemplate template to be parsed (string) |
74 @return parsed template (string) |
80 @return parsed template (string) |
75 """ |
81 """ |
76 locale = QLocale(Preferences.getWebBrowser("SearchLanguage")) |
82 locale = QLocale(Preferences.getWebBrowser("SearchLanguage")) |
77 language = locale.name().replace("_", "-") |
83 language = locale.name().replace("_", "-") |
78 country = locale.name().split("_")[0].lower() |
84 country = locale.name().split("_")[0].lower() |
79 |
85 |
80 result = searchTemplate |
86 result = searchTemplate |
81 result = result.replace("{count}", "20") |
87 result = result.replace("{count}", "20") |
82 result = result.replace("{startIndex}", "0") |
88 result = result.replace("{startIndex}", "0") |
83 result = result.replace("{startPage}", "0") |
89 result = result.replace("{startPage}", "0") |
84 result = result.replace("{language}", language) |
90 result = result.replace("{language}", language) |
85 result = result.replace("{country}", country) |
91 result = result.replace("{country}", country) |
86 result = result.replace("{inputEncoding}", "UTF-8") |
92 result = result.replace("{inputEncoding}", "UTF-8") |
87 result = result.replace("{outputEncoding}", "UTF-8") |
93 result = result.replace("{outputEncoding}", "UTF-8") |
88 result = result.replace( |
94 result = result.replace( |
89 "{searchTerms}", |
95 "{searchTerms}", bytes(QUrl.toPercentEncoding(searchTerm)).decode() |
90 bytes(QUrl.toPercentEncoding(searchTerm)).decode()) |
96 ) |
91 result = re.sub(r"""\{([^\}]*:|)source\??\}""", Program, result) |
97 result = re.sub(r"""\{([^\}]*:|)source\??\}""", Program, result) |
92 |
98 |
93 return result |
99 return result |
94 |
100 |
95 @pyqtSlot(result=str) |
101 @pyqtSlot(result=str) |
96 def name(self): |
102 def name(self): |
97 """ |
103 """ |
98 Public method to get the name of the engine. |
104 Public method to get the name of the engine. |
99 |
105 |
100 @return name of the engine (string) |
106 @return name of the engine (string) |
101 """ |
107 """ |
102 return self._name |
108 return self._name |
103 |
109 |
104 def setName(self, name): |
110 def setName(self, name): |
105 """ |
111 """ |
106 Public method to set the engine name. |
112 Public method to set the engine name. |
107 |
113 |
108 @param name name of the engine (string) |
114 @param name name of the engine (string) |
109 """ |
115 """ |
110 self._name = name |
116 self._name = name |
111 |
117 |
112 def description(self): |
118 def description(self): |
113 """ |
119 """ |
114 Public method to get the description of the engine. |
120 Public method to get the description of the engine. |
115 |
121 |
116 @return description of the engine (string) |
122 @return description of the engine (string) |
117 """ |
123 """ |
118 return self._description |
124 return self._description |
119 |
125 |
120 def setDescription(self, description): |
126 def setDescription(self, description): |
121 """ |
127 """ |
122 Public method to set the engine description. |
128 Public method to set the engine description. |
123 |
129 |
124 @param description description of the engine (string) |
130 @param description description of the engine (string) |
125 """ |
131 """ |
126 self._description = description |
132 self._description = description |
127 |
133 |
128 def searchUrlTemplate(self): |
134 def searchUrlTemplate(self): |
129 """ |
135 """ |
130 Public method to get the search URL template of the engine. |
136 Public method to get the search URL template of the engine. |
131 |
137 |
132 @return search URL template of the engine (string) |
138 @return search URL template of the engine (string) |
133 """ |
139 """ |
134 return self._searchUrlTemplate |
140 return self._searchUrlTemplate |
135 |
141 |
136 def setSearchUrlTemplate(self, searchUrlTemplate): |
142 def setSearchUrlTemplate(self, searchUrlTemplate): |
137 """ |
143 """ |
138 Public method to set the engine search URL template. |
144 Public method to set the engine search URL template. |
139 |
145 |
140 The URL template is processed according to the specification: |
146 The URL template is processed according to the specification: |
141 <a |
147 <a |
142 href="http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax"> |
148 href="http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax"> |
143 http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax</a> |
149 http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax</a> |
144 |
150 |
157 <tr><td>{outputEncoding}</td><td>UTF-8</td></tr> |
163 <tr><td>{outputEncoding}</td><td>UTF-8</td></tr> |
158 <tr><td>{searchTerms}</td><td>the string supplied by the user</td></tr> |
164 <tr><td>{searchTerms}</td><td>the string supplied by the user</td></tr> |
159 <tr><td>{*:source}</td> |
165 <tr><td>{*:source}</td> |
160 <td>application name, QCoreApplication::applicationName()</td></tr> |
166 <td>application name, QCoreApplication::applicationName()</td></tr> |
161 </table> |
167 </table> |
162 |
168 |
163 @param searchUrlTemplate search URL template of the engine (string) |
169 @param searchUrlTemplate search URL template of the engine (string) |
164 """ |
170 """ |
165 self._searchUrlTemplate = searchUrlTemplate |
171 self._searchUrlTemplate = searchUrlTemplate |
166 |
172 |
167 def searchUrl(self, searchTerm): |
173 def searchUrl(self, searchTerm): |
168 """ |
174 """ |
169 Public method to get a URL ready for searching. |
175 Public method to get a URL ready for searching. |
170 |
176 |
171 @param searchTerm term to search for (string) |
177 @param searchTerm term to search for (string) |
172 @return URL (QUrl) |
178 @return URL (QUrl) |
173 """ |
179 """ |
174 if not self._searchUrlTemplate: |
180 if not self._searchUrlTemplate: |
175 return QUrl() |
181 return QUrl() |
176 |
182 |
177 ret = QUrl.fromEncoded( |
183 ret = QUrl.fromEncoded( |
178 self.parseTemplate(searchTerm, self._searchUrlTemplate) |
184 self.parseTemplate(searchTerm, self._searchUrlTemplate).encode("utf-8") |
179 .encode("utf-8")) |
185 ) |
180 |
186 |
181 if self.__searchMethod != "post": |
187 if self.__searchMethod != "post": |
182 urlQuery = QUrlQuery(ret) |
188 urlQuery = QUrlQuery(ret) |
183 for parameter in self._searchParameters: |
189 for parameter in self._searchParameters: |
184 urlQuery.addQueryItem( |
190 urlQuery.addQueryItem( |
185 parameter[0], |
191 parameter[0], self.parseTemplate(searchTerm, parameter[1]) |
186 self.parseTemplate(searchTerm, parameter[1])) |
192 ) |
187 ret.setQuery(urlQuery) |
193 ret.setQuery(urlQuery) |
188 |
194 |
189 return ret |
195 return ret |
190 |
196 |
191 def providesSuggestions(self): |
197 def providesSuggestions(self): |
192 """ |
198 """ |
193 Public method to check, if the engine provides suggestions. |
199 Public method to check, if the engine provides suggestions. |
194 |
200 |
195 @return flag indicating suggestions are provided (boolean) |
201 @return flag indicating suggestions are provided (boolean) |
196 """ |
202 """ |
197 return self._suggestionsUrlTemplate != "" |
203 return self._suggestionsUrlTemplate != "" |
198 |
204 |
199 def suggestionsUrlTemplate(self): |
205 def suggestionsUrlTemplate(self): |
200 """ |
206 """ |
201 Public method to get the search URL template of the engine. |
207 Public method to get the search URL template of the engine. |
202 |
208 |
203 @return search URL template of the engine (string) |
209 @return search URL template of the engine (string) |
204 """ |
210 """ |
205 return self._suggestionsUrlTemplate |
211 return self._suggestionsUrlTemplate |
206 |
212 |
207 def setSuggestionsUrlTemplate(self, suggestionsUrlTemplate): |
213 def setSuggestionsUrlTemplate(self, suggestionsUrlTemplate): |
208 """ |
214 """ |
209 Public method to set the engine suggestions URL template. |
215 Public method to set the engine suggestions URL template. |
210 |
216 |
211 @param suggestionsUrlTemplate suggestions URL template of the |
217 @param suggestionsUrlTemplate suggestions URL template of the |
212 engine (string) |
218 engine (string) |
213 """ |
219 """ |
214 self._suggestionsUrlTemplate = suggestionsUrlTemplate |
220 self._suggestionsUrlTemplate = suggestionsUrlTemplate |
215 |
221 |
216 def suggestionsUrl(self, searchTerm): |
222 def suggestionsUrl(self, searchTerm): |
217 """ |
223 """ |
218 Public method to get a URL ready for suggestions. |
224 Public method to get a URL ready for suggestions. |
219 |
225 |
220 @param searchTerm term to search for (string) |
226 @param searchTerm term to search for (string) |
221 @return URL (QUrl) |
227 @return URL (QUrl) |
222 """ |
228 """ |
223 if not self._suggestionsUrlTemplate: |
229 if not self._suggestionsUrlTemplate: |
224 return QUrl() |
230 return QUrl() |
225 |
231 |
226 ret = QUrl.fromEncoded(QByteArray(self.parseTemplate( |
232 ret = QUrl.fromEncoded( |
227 searchTerm, self._suggestionsUrlTemplate).encode("utf-8"))) |
233 QByteArray( |
228 |
234 self.parseTemplate(searchTerm, self._suggestionsUrlTemplate).encode( |
|
235 "utf-8" |
|
236 ) |
|
237 ) |
|
238 ) |
|
239 |
229 if self.__searchMethod != "post": |
240 if self.__searchMethod != "post": |
230 urlQuery = QUrlQuery(ret) |
241 urlQuery = QUrlQuery(ret) |
231 for parameter in self._suggestionsParameters: |
242 for parameter in self._suggestionsParameters: |
232 urlQuery.addQueryItem( |
243 urlQuery.addQueryItem( |
233 parameter[0], |
244 parameter[0], self.parseTemplate(searchTerm, parameter[1]) |
234 self.parseTemplate(searchTerm, parameter[1])) |
245 ) |
235 ret.setQuery(urlQuery) |
246 ret.setQuery(urlQuery) |
236 |
247 |
237 return ret |
248 return ret |
238 |
249 |
239 def searchParameters(self): |
250 def searchParameters(self): |
240 """ |
251 """ |
241 Public method to get the search parameters of the engine. |
252 Public method to get the search parameters of the engine. |
242 |
253 |
243 @return search parameters of the engine (list of two tuples) |
254 @return search parameters of the engine (list of two tuples) |
244 """ |
255 """ |
245 return self._searchParameters[:] |
256 return self._searchParameters[:] |
246 |
257 |
247 def setSearchParameters(self, searchParameters): |
258 def setSearchParameters(self, searchParameters): |
248 """ |
259 """ |
249 Public method to set the engine search parameters. |
260 Public method to set the engine search parameters. |
250 |
261 |
251 @param searchParameters search parameters of the engine |
262 @param searchParameters search parameters of the engine |
252 (list of two tuples) |
263 (list of two tuples) |
253 """ |
264 """ |
254 self._searchParameters = searchParameters[:] |
265 self._searchParameters = searchParameters[:] |
255 |
266 |
256 def suggestionsParameters(self): |
267 def suggestionsParameters(self): |
257 """ |
268 """ |
258 Public method to get the suggestions parameters of the engine. |
269 Public method to get the suggestions parameters of the engine. |
259 |
270 |
260 @return suggestions parameters of the engine (list of two tuples) |
271 @return suggestions parameters of the engine (list of two tuples) |
261 """ |
272 """ |
262 return self._suggestionsParameters[:] |
273 return self._suggestionsParameters[:] |
263 |
274 |
264 def setSuggestionsParameters(self, suggestionsParameters): |
275 def setSuggestionsParameters(self, suggestionsParameters): |
265 """ |
276 """ |
266 Public method to set the engine suggestions parameters. |
277 Public method to set the engine suggestions parameters. |
267 |
278 |
268 @param suggestionsParameters suggestions parameters of the |
279 @param suggestionsParameters suggestions parameters of the |
269 engine (list of two tuples) |
280 engine (list of two tuples) |
270 """ |
281 """ |
271 self._suggestionsParameters = suggestionsParameters[:] |
282 self._suggestionsParameters = suggestionsParameters[:] |
272 |
283 |
273 def searchMethod(self): |
284 def searchMethod(self): |
274 """ |
285 """ |
275 Public method to get the HTTP request method used to perform search |
286 Public method to get the HTTP request method used to perform search |
276 requests. |
287 requests. |
277 |
288 |
278 @return HTTP request method (string) |
289 @return HTTP request method (string) |
279 """ |
290 """ |
280 return self.__searchMethod |
291 return self.__searchMethod |
281 |
292 |
282 def setSearchMethod(self, method): |
293 def setSearchMethod(self, method): |
283 """ |
294 """ |
284 Public method to set the HTTP request method used to perform search |
295 Public method to set the HTTP request method used to perform search |
285 requests. |
296 requests. |
286 |
297 |
287 @param method HTTP request method (string) |
298 @param method HTTP request method (string) |
288 """ |
299 """ |
289 requestMethod = method.lower() |
300 requestMethod = method.lower() |
290 if requestMethod not in self.__requestMethods: |
301 if requestMethod not in self.__requestMethods: |
291 return |
302 return |
292 |
303 |
293 self.__searchMethod = requestMethod |
304 self.__searchMethod = requestMethod |
294 |
305 |
295 def suggestionsMethod(self): |
306 def suggestionsMethod(self): |
296 """ |
307 """ |
297 Public method to get the HTTP request method used to perform |
308 Public method to get the HTTP request method used to perform |
298 suggestions requests. |
309 suggestions requests. |
299 |
310 |
300 @return HTTP request method (string) |
311 @return HTTP request method (string) |
301 """ |
312 """ |
302 return self.__suggestionsMethod |
313 return self.__suggestionsMethod |
303 |
314 |
304 def setSuggestionsMethod(self, method): |
315 def setSuggestionsMethod(self, method): |
305 """ |
316 """ |
306 Public method to set the HTTP request method used to perform |
317 Public method to set the HTTP request method used to perform |
307 suggestions requests. |
318 suggestions requests. |
308 |
319 |
309 @param method HTTP request method (string) |
320 @param method HTTP request method (string) |
310 """ |
321 """ |
311 requestMethod = method.lower() |
322 requestMethod = method.lower() |
312 if requestMethod not in self.__requestMethods: |
323 if requestMethod not in self.__requestMethods: |
313 return |
324 return |
314 |
325 |
315 self.__suggestionsMethod = requestMethod |
326 self.__suggestionsMethod = requestMethod |
316 |
327 |
317 def imageUrl(self): |
328 def imageUrl(self): |
318 """ |
329 """ |
319 Public method to get the image URL of the engine. |
330 Public method to get the image URL of the engine. |
320 |
331 |
321 @return image URL of the engine (string) |
332 @return image URL of the engine (string) |
322 """ |
333 """ |
323 return self._imageUrl |
334 return self._imageUrl |
324 |
335 |
325 def setImageUrl(self, imageUrl): |
336 def setImageUrl(self, imageUrl): |
326 """ |
337 """ |
327 Public method to set the engine image URL. |
338 Public method to set the engine image URL. |
328 |
339 |
329 @param imageUrl image URL of the engine (string) |
340 @param imageUrl image URL of the engine (string) |
330 """ |
341 """ |
331 self._imageUrl = imageUrl |
342 self._imageUrl = imageUrl |
332 |
343 |
333 def setImageUrlAndLoad(self, imageUrl): |
344 def setImageUrlAndLoad(self, imageUrl): |
334 """ |
345 """ |
335 Public method to set the engine image URL. |
346 Public method to set the engine image URL. |
336 |
347 |
337 @param imageUrl image URL of the engine (string) |
348 @param imageUrl image URL of the engine (string) |
338 """ |
349 """ |
339 self.setImageUrl(imageUrl) |
350 self.setImageUrl(imageUrl) |
340 self.__iconMoved = False |
351 self.__iconMoved = False |
341 self.loadImage() |
352 self.loadImage() |
342 |
353 |
343 def loadImage(self): |
354 def loadImage(self): |
344 """ |
355 """ |
345 Public method to load the image of the engine. |
356 Public method to load the image of the engine. |
346 """ |
357 """ |
347 if self.__networkAccessManager is None or not self._imageUrl: |
358 if self.__networkAccessManager is None or not self._imageUrl: |
348 return |
359 return |
349 |
360 |
350 reply = self.__networkAccessManager.get( |
361 reply = self.__networkAccessManager.get( |
351 QNetworkRequest(QUrl.fromEncoded(self._imageUrl.encode("utf-8")))) |
362 QNetworkRequest(QUrl.fromEncoded(self._imageUrl.encode("utf-8"))) |
|
363 ) |
352 reply.finished.connect(lambda: self.__imageObtained(reply)) |
364 reply.finished.connect(lambda: self.__imageObtained(reply)) |
353 self.__replies.append(reply) |
365 self.__replies.append(reply) |
354 |
366 |
355 def __imageObtained(self, reply): |
367 def __imageObtained(self, reply): |
356 """ |
368 """ |
357 Private slot to receive the image of the engine. |
369 Private slot to receive the image of the engine. |
358 |
370 |
359 @param reply reference to the network reply |
371 @param reply reference to the network reply |
360 @type QNetworkReply |
372 @type QNetworkReply |
361 """ |
373 """ |
362 response = reply.readAll() |
374 response = reply.readAll() |
363 |
375 |
364 reply.close() |
376 reply.close() |
365 if reply in self.__replies: |
377 if reply in self.__replies: |
366 self.__replies.remove(reply) |
378 self.__replies.remove(reply) |
367 reply.deleteLater() |
379 reply.deleteLater() |
368 |
380 |
369 if response.isEmpty(): |
381 if response.isEmpty(): |
370 return |
382 return |
371 |
383 |
372 if response.startsWith(b"<html>") or response.startsWith(b"HTML"): |
384 if response.startsWith(b"<html>") or response.startsWith(b"HTML"): |
373 self.__iconMoved = True |
385 self.__iconMoved = True |
374 self.__image = QImage() |
386 self.__image = QImage() |
375 else: |
387 else: |
376 self.__image.loadFromData(response) |
388 self.__image.loadFromData(response) |
377 self.imageChanged.emit() |
389 self.imageChanged.emit() |
378 |
390 |
379 def image(self): |
391 def image(self): |
380 """ |
392 """ |
381 Public method to get the image of the engine. |
393 Public method to get the image of the engine. |
382 |
394 |
383 @return image of the engine (QImage) |
395 @return image of the engine (QImage) |
384 """ |
396 """ |
385 if not self.__iconMoved and self.__image.isNull(): |
397 if not self.__iconMoved and self.__image.isNull(): |
386 self.loadImage() |
398 self.loadImage() |
387 |
399 |
388 return self.__image |
400 return self.__image |
389 |
401 |
390 def setImage(self, image): |
402 def setImage(self, image): |
391 """ |
403 """ |
392 Public method to set the image of the engine. |
404 Public method to set the image of the engine. |
393 |
405 |
394 @param image image to be set (QImage) |
406 @param image image to be set (QImage) |
395 """ |
407 """ |
396 if not self._imageUrl: |
408 if not self._imageUrl: |
397 imageBuffer = QBuffer() |
409 imageBuffer = QBuffer() |
398 imageBuffer.open(QIODevice.OpenModeFlag.ReadWrite) |
410 imageBuffer.open(QIODevice.OpenModeFlag.ReadWrite) |
399 if image.save(imageBuffer, "PNG"): |
411 if image.save(imageBuffer, "PNG"): |
400 self._imageUrl = "data:image/png;base64,{0}".format( |
412 self._imageUrl = "data:image/png;base64,{0}".format( |
401 bytes(imageBuffer.buffer().toBase64()).decode()) |
413 bytes(imageBuffer.buffer().toBase64()).decode() |
402 |
414 ) |
|
415 |
403 self.__image = QImage(image) |
416 self.__image = QImage(image) |
404 self.imageChanged.emit() |
417 self.imageChanged.emit() |
405 |
418 |
406 def isValid(self): |
419 def isValid(self): |
407 """ |
420 """ |
408 Public method to check, if the engine is valid. |
421 Public method to check, if the engine is valid. |
409 |
422 |
410 @return flag indicating validity (boolean) |
423 @return flag indicating validity (boolean) |
411 """ |
424 """ |
412 return self._name and self._searchUrlTemplate |
425 return self._name and self._searchUrlTemplate |
413 |
426 |
414 def __eq__(self, other): |
427 def __eq__(self, other): |
415 """ |
428 """ |
416 Special method implementing the == operator. |
429 Special method implementing the == operator. |
417 |
430 |
418 @param other reference to an open search engine (OpenSearchEngine) |
431 @param other reference to an open search engine (OpenSearchEngine) |
419 @return flag indicating equality (boolean) |
432 @return flag indicating equality (boolean) |
420 """ |
433 """ |
421 if not isinstance(other, OpenSearchEngine): |
434 if not isinstance(other, OpenSearchEngine): |
422 return NotImplemented |
435 return NotImplemented |
423 |
436 |
424 return ( |
437 return ( |
425 self._name == other._name and |
438 self._name == other._name |
426 self._description == other._description and |
439 and self._description == other._description |
427 self._imageUrl == other._imageUrl and |
440 and self._imageUrl == other._imageUrl |
428 self._searchUrlTemplate == other._searchUrlTemplate and |
441 and self._searchUrlTemplate == other._searchUrlTemplate |
429 self._suggestionsUrlTemplate == other._suggestionsUrlTemplate and |
442 and self._suggestionsUrlTemplate == other._suggestionsUrlTemplate |
430 self._searchParameters == other._searchParameters and |
443 and self._searchParameters == other._searchParameters |
431 self._suggestionsParameters == other._suggestionsParameters |
444 and self._suggestionsParameters == other._suggestionsParameters |
432 ) |
445 ) |
433 |
446 |
434 def __lt__(self, other): |
447 def __lt__(self, other): |
435 """ |
448 """ |
436 Special method implementing the < operator. |
449 Special method implementing the < operator. |
437 |
450 |
438 @param other reference to an open search engine (OpenSearchEngine) |
451 @param other reference to an open search engine (OpenSearchEngine) |
439 @return flag indicating less than (boolean) |
452 @return flag indicating less than (boolean) |
440 """ |
453 """ |
441 if not isinstance(other, OpenSearchEngine): |
454 if not isinstance(other, OpenSearchEngine): |
442 return NotImplemented |
455 return NotImplemented |
443 |
456 |
444 return self._name < other._name |
457 return self._name < other._name |
445 |
458 |
446 def requestSuggestions(self, searchTerm): |
459 def requestSuggestions(self, searchTerm): |
447 """ |
460 """ |
448 Public method to request suggestions. |
461 Public method to request suggestions. |
449 |
462 |
450 @param searchTerm term to get suggestions for (string) |
463 @param searchTerm term to get suggestions for (string) |
451 """ |
464 """ |
452 if not searchTerm or not self.providesSuggestions(): |
465 if not searchTerm or not self.providesSuggestions(): |
453 return |
466 return |
454 |
467 |
455 if self.__networkAccessManager is None: |
468 if self.__networkAccessManager is None: |
456 return |
469 return |
457 |
470 |
458 if self.__suggestionsReply is not None: |
471 if self.__suggestionsReply is not None: |
459 self.__suggestionsReply.finished.disconnect( |
472 self.__suggestionsReply.finished.disconnect(self.__suggestionsObtained) |
460 self.__suggestionsObtained) |
|
461 self.__suggestionsReply.abort() |
473 self.__suggestionsReply.abort() |
462 self.__suggestionsReply.deleteLater() |
474 self.__suggestionsReply.deleteLater() |
463 self.__suggestionsReply = None |
475 self.__suggestionsReply = None |
464 |
476 |
465 if self.__suggestionsMethod not in self.__requestMethods: |
477 if self.__suggestionsMethod not in self.__requestMethods: |
466 # ignore |
478 # ignore |
467 return |
479 return |
468 |
480 |
469 if self.__suggestionsMethod == "get": |
481 if self.__suggestionsMethod == "get": |
470 self.__suggestionsReply = self.networkAccessManager().get( |
482 self.__suggestionsReply = self.networkAccessManager().get( |
471 QNetworkRequest(self.suggestionsUrl(searchTerm))) |
483 QNetworkRequest(self.suggestionsUrl(searchTerm)) |
|
484 ) |
472 else: |
485 else: |
473 parameters = [] |
486 parameters = [] |
474 for parameter in self._suggestionsParameters: |
487 for parameter in self._suggestionsParameters: |
475 parameters.append(parameter[0] + "=" + parameter[1]) |
488 parameters.append(parameter[0] + "=" + parameter[1]) |
476 data = "&".join(parameters) |
489 data = "&".join(parameters) |
477 self.__suggestionsReply = self.networkAccessManager().post( |
490 self.__suggestionsReply = self.networkAccessManager().post( |
478 QNetworkRequest(self.suggestionsUrl(searchTerm)), data) |
491 QNetworkRequest(self.suggestionsUrl(searchTerm)), data |
479 self.__suggestionsReply.finished.connect( |
492 ) |
480 self.__suggestionsObtained) |
493 self.__suggestionsReply.finished.connect(self.__suggestionsObtained) |
481 |
494 |
482 def __suggestionsObtained(self): |
495 def __suggestionsObtained(self): |
483 """ |
496 """ |
484 Private slot to receive the suggestions. |
497 Private slot to receive the suggestions. |
485 """ |
498 """ |
486 if ( |
499 if self.__suggestionsReply.error() == QNetworkReply.NetworkError.NoError: |
487 self.__suggestionsReply.error() == |
|
488 QNetworkReply.NetworkError.NoError |
|
489 ): |
|
490 buffer = bytes(self.__suggestionsReply.readAll()) |
500 buffer = bytes(self.__suggestionsReply.readAll()) |
491 response = Utilities.decodeBytes(buffer) |
501 response = Utilities.decodeBytes(buffer) |
492 response = response.strip() |
502 response = response.strip() |
493 |
503 |
494 self.__suggestionsReply.close() |
504 self.__suggestionsReply.close() |
495 self.__suggestionsReply.deleteLater() |
505 self.__suggestionsReply.deleteLater() |
496 self.__suggestionsReply = None |
506 self.__suggestionsReply = None |
497 |
507 |
498 if len(response) == 0: |
508 if len(response) == 0: |
499 return |
509 return |
500 |
510 |
501 try: |
511 try: |
502 result = json.loads(response) |
512 result = json.loads(response) |
503 except ValueError: |
513 except ValueError: |
504 return |
514 return |
505 |
515 |
506 try: |
516 try: |
507 suggestions = result[1] |
517 suggestions = result[1] |
508 except IndexError: |
518 except IndexError: |
509 return |
519 return |
510 |
520 |
511 self.suggestions.emit(suggestions) |
521 self.suggestions.emit(suggestions) |
512 |
522 |
513 def networkAccessManager(self): |
523 def networkAccessManager(self): |
514 """ |
524 """ |
515 Public method to get a reference to the network access manager object. |
525 Public method to get a reference to the network access manager object. |
516 |
526 |
517 @return reference to the network access manager object |
527 @return reference to the network access manager object |
518 (QNetworkAccessManager) |
528 (QNetworkAccessManager) |
519 """ |
529 """ |
520 return self.__networkAccessManager |
530 return self.__networkAccessManager |
521 |
531 |
522 def setNetworkAccessManager(self, networkAccessManager): |
532 def setNetworkAccessManager(self, networkAccessManager): |
523 """ |
533 """ |
524 Public method to set the reference to the network access manager. |
534 Public method to set the reference to the network access manager. |
525 |
535 |
526 @param networkAccessManager reference to the network access manager |
536 @param networkAccessManager reference to the network access manager |
527 object (QNetworkAccessManager) |
537 object (QNetworkAccessManager) |
528 """ |
538 """ |
529 self.__networkAccessManager = networkAccessManager |
539 self.__networkAccessManager = networkAccessManager |