src/eric7/WebBrowser/OpenSearch/OpenSearchManager.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
8 """ 8 """
9 9
10 import os 10 import os
11 import contextlib 11 import contextlib
12 12
13 from PyQt6.QtCore import ( 13 from PyQt6.QtCore import pyqtSignal, QObject, QUrl, QFile, QDir, QIODevice, QUrlQuery
14 pyqtSignal, QObject, QUrl, QFile, QDir, QIODevice, QUrlQuery
15 )
16 from PyQt6.QtWidgets import QLineEdit, QInputDialog 14 from PyQt6.QtWidgets import QLineEdit, QInputDialog
17 from PyQt6.QtNetwork import QNetworkRequest, QNetworkReply 15 from PyQt6.QtNetwork import QNetworkRequest, QNetworkReply
18 16
19 from EricWidgets.EricApplication import ericApp 17 from EricWidgets.EricApplication import ericApp
20 from EricWidgets import EricMessageBox 18 from EricWidgets import EricMessageBox
25 23
26 24
27 class OpenSearchManager(QObject): 25 class OpenSearchManager(QObject):
28 """ 26 """
29 Class implementing a manager for open search engines. 27 Class implementing a manager for open search engines.
30 28
31 @signal changed() emitted to indicate a change 29 @signal changed() emitted to indicate a change
32 @signal currentEngineChanged() emitted to indicate a change of 30 @signal currentEngineChanged() emitted to indicate a change of
33 the current search engine 31 the current search engine
34 """ 32 """
33
35 changed = pyqtSignal() 34 changed = pyqtSignal()
36 currentEngineChanged = pyqtSignal() 35 currentEngineChanged = pyqtSignal()
37 36
38 def __init__(self, parent=None): 37 def __init__(self, parent=None):
39 """ 38 """
40 Constructor 39 Constructor
41 40
42 @param parent reference to the parent object (QObject) 41 @param parent reference to the parent object (QObject)
43 """ 42 """
44 if parent is None: 43 if parent is None:
45 parent = ericApp() 44 parent = ericApp()
46 super().__init__(parent) 45 super().__init__(parent)
47 46
48 self.__replies = [] 47 self.__replies = []
49 self.__engines = {} 48 self.__engines = {}
50 self.__keywords = {} 49 self.__keywords = {}
51 self.__current = "" 50 self.__current = ""
52 self.__loading = False 51 self.__loading = False
53 self.__saveTimer = AutoSaver(self, self.save) 52 self.__saveTimer = AutoSaver(self, self.save)
54 53
55 self.changed.connect(self.__saveTimer.changeOccurred) 54 self.changed.connect(self.__saveTimer.changeOccurred)
56 55
57 self.load() 56 self.load()
58 57
59 def close(self): 58 def close(self):
60 """ 59 """
61 Public method to close the open search engines manager. 60 Public method to close the open search engines manager.
62 """ 61 """
63 self.__saveTimer.saveIfNeccessary() 62 self.__saveTimer.saveIfNeccessary()
64 63
65 def currentEngineName(self): 64 def currentEngineName(self):
66 """ 65 """
67 Public method to get the name of the current search engine. 66 Public method to get the name of the current search engine.
68 67
69 @return name of the current search engine (string) 68 @return name of the current search engine (string)
70 """ 69 """
71 return self.__current 70 return self.__current
72 71
73 def setCurrentEngineName(self, name): 72 def setCurrentEngineName(self, name):
74 """ 73 """
75 Public method to set the current engine by name. 74 Public method to set the current engine by name.
76 75
77 @param name name of the new current engine (string) 76 @param name name of the new current engine (string)
78 """ 77 """
79 if name not in self.__engines: 78 if name not in self.__engines:
80 return 79 return
81 80
82 self.__current = name 81 self.__current = name
83 self.currentEngineChanged.emit() 82 self.currentEngineChanged.emit()
84 self.changed.emit() 83 self.changed.emit()
85 84
86 def currentEngine(self): 85 def currentEngine(self):
87 """ 86 """
88 Public method to get a reference to the current engine. 87 Public method to get a reference to the current engine.
89 88
90 @return reference to the current engine (OpenSearchEngine) 89 @return reference to the current engine (OpenSearchEngine)
91 """ 90 """
92 if not self.__current or self.__current not in self.__engines: 91 if not self.__current or self.__current not in self.__engines:
93 return None 92 return None
94 93
95 return self.__engines[self.__current] 94 return self.__engines[self.__current]
96 95
97 def setCurrentEngine(self, engine): 96 def setCurrentEngine(self, engine):
98 """ 97 """
99 Public method to set the current engine. 98 Public method to set the current engine.
100 99
101 @param engine reference to the new current engine (OpenSearchEngine) 100 @param engine reference to the new current engine (OpenSearchEngine)
102 """ 101 """
103 if engine is None: 102 if engine is None:
104 return 103 return
105 104
106 for engineName in self.__engines: 105 for engineName in self.__engines:
107 if self.__engines[engineName] == engine: 106 if self.__engines[engineName] == engine:
108 self.setCurrentEngineName(engineName) 107 self.setCurrentEngineName(engineName)
109 break 108 break
110 109
111 def engine(self, name): 110 def engine(self, name):
112 """ 111 """
113 Public method to get a reference to the named engine. 112 Public method to get a reference to the named engine.
114 113
115 @param name name of the engine (string) 114 @param name name of the engine (string)
116 @return reference to the engine (OpenSearchEngine) 115 @return reference to the engine (OpenSearchEngine)
117 """ 116 """
118 if name not in self.__engines: 117 if name not in self.__engines:
119 return None 118 return None
120 119
121 return self.__engines[name] 120 return self.__engines[name]
122 121
123 def engineExists(self, name): 122 def engineExists(self, name):
124 """ 123 """
125 Public method to check, if an engine exists. 124 Public method to check, if an engine exists.
126 125
127 @param name name of the engine (string) 126 @param name name of the engine (string)
128 @return flag indicating an existing engine (boolean) 127 @return flag indicating an existing engine (boolean)
129 """ 128 """
130 return name in self.__engines 129 return name in self.__engines
131 130
132 def allEnginesNames(self): 131 def allEnginesNames(self):
133 """ 132 """
134 Public method to get a list of all engine names. 133 Public method to get a list of all engine names.
135 134
136 @return sorted list of all engine names (list of strings) 135 @return sorted list of all engine names (list of strings)
137 """ 136 """
138 return sorted(self.__engines.keys()) 137 return sorted(self.__engines.keys())
139 138
140 def enginesCount(self): 139 def enginesCount(self):
141 """ 140 """
142 Public method to get the number of available engines. 141 Public method to get the number of available engines.
143 142
144 @return number of engines (integer) 143 @return number of engines (integer)
145 """ 144 """
146 return len(self.__engines) 145 return len(self.__engines)
147 146
148 def addEngine(self, engine): 147 def addEngine(self, engine):
149 """ 148 """
150 Public method to add a new search engine. 149 Public method to add a new search engine.
151 150
152 @param engine URL of the engine definition file (QUrl) or 151 @param engine URL of the engine definition file (QUrl) or
153 name of a file containing the engine definition (string) 152 name of a file containing the engine definition (string)
154 or reference to an engine object (OpenSearchEngine) 153 or reference to an engine object (OpenSearchEngine)
155 @return flag indicating success (boolean) 154 @return flag indicating success (boolean)
156 """ 155 """
157 from .OpenSearchEngine import OpenSearchEngine 156 from .OpenSearchEngine import OpenSearchEngine
157
158 if isinstance(engine, QUrl): 158 if isinstance(engine, QUrl):
159 return self.__addEngineByUrl(engine) 159 return self.__addEngineByUrl(engine)
160 elif isinstance(engine, OpenSearchEngine): 160 elif isinstance(engine, OpenSearchEngine):
161 return self.__addEngineByEngine(engine) 161 return self.__addEngineByEngine(engine)
162 else: 162 else:
163 return self.__addEngineByFile(engine) 163 return self.__addEngineByFile(engine)
164 164
165 def __addEngineByUrl(self, url): 165 def __addEngineByUrl(self, url):
166 """ 166 """
167 Private method to add a new search engine given its URL. 167 Private method to add a new search engine given its URL.
168 168
169 @param url URL of the engine definition file (QUrl) 169 @param url URL of the engine definition file (QUrl)
170 @return flag indicating success (boolean) 170 @return flag indicating success (boolean)
171 """ 171 """
172 if not url.isValid(): 172 if not url.isValid():
173 return False 173 return False
174 174
175 from WebBrowser.WebBrowserWindow import WebBrowserWindow 175 from WebBrowser.WebBrowserWindow import WebBrowserWindow
176 176
177 reply = WebBrowserWindow.networkManager().get(QNetworkRequest(url)) 177 reply = WebBrowserWindow.networkManager().get(QNetworkRequest(url))
178 reply.finished.connect(lambda: self.__engineFromUrlAvailable(reply)) 178 reply.finished.connect(lambda: self.__engineFromUrlAvailable(reply))
179 reply.setParent(self) 179 reply.setParent(self)
180 self.__replies.append(reply) 180 self.__replies.append(reply)
181 181
182 return True 182 return True
183 183
184 def __addEngineByFile(self, filename): 184 def __addEngineByFile(self, filename):
185 """ 185 """
186 Private method to add a new search engine given a filename. 186 Private method to add a new search engine given a filename.
187 187
188 @param filename name of a file containing the engine definition 188 @param filename name of a file containing the engine definition
189 (string) 189 (string)
190 @return flag indicating success (boolean) 190 @return flag indicating success (boolean)
191 """ 191 """
192 file_ = QFile(filename) 192 file_ = QFile(filename)
193 if not file_.open(QIODevice.OpenModeFlag.ReadOnly): 193 if not file_.open(QIODevice.OpenModeFlag.ReadOnly):
194 return False 194 return False
195 195
196 from .OpenSearchReader import OpenSearchReader 196 from .OpenSearchReader import OpenSearchReader
197
197 reader = OpenSearchReader() 198 reader = OpenSearchReader()
198 engine = reader.read(file_) 199 engine = reader.read(file_)
199 200
200 if not self.__addEngineByEngine(engine): 201 if not self.__addEngineByEngine(engine):
201 return False 202 return False
202 203
203 return True 204 return True
204 205
205 def __addEngineByEngine(self, engine): 206 def __addEngineByEngine(self, engine):
206 """ 207 """
207 Private method to add a new search engine given a reference to an 208 Private method to add a new search engine given a reference to an
208 engine. 209 engine.
209 210
210 @param engine reference to an engine object (OpenSearchEngine) 211 @param engine reference to an engine object (OpenSearchEngine)
211 @return flag indicating success (boolean) 212 @return flag indicating success (boolean)
212 """ 213 """
213 if engine is None: 214 if engine is None:
214 return False 215 return False
215 216
216 if not engine.isValid(): 217 if not engine.isValid():
217 return False 218 return False
218 219
219 if engine.name() in self.__engines: 220 if engine.name() in self.__engines:
220 return False 221 return False
221 222
222 engine.setParent(self) 223 engine.setParent(self)
223 self.__engines[engine.name()] = engine 224 self.__engines[engine.name()] = engine
224 225
225 self.changed.emit() 226 self.changed.emit()
226 227
227 return True 228 return True
228 229
229 def addEngineFromForm(self, res, view): 230 def addEngineFromForm(self, res, view):
230 """ 231 """
231 Public method to add a new search engine from a form. 232 Public method to add a new search engine from a form.
232 233
233 @param res result of the JavaScript run on by 234 @param res result of the JavaScript run on by
234 WebBrowserView.__addSearchEngine() 235 WebBrowserView.__addSearchEngine()
235 @type dict or None 236 @type dict or None
236 @param view reference to the web browser view 237 @param view reference to the web browser view
237 @type WebBrowserView 238 @type WebBrowserView
238 """ 239 """
239 if not res: 240 if not res:
240 return 241 return
241 242
242 method = res["method"] 243 method = res["method"]
243 actionUrl = QUrl(res["action"]) 244 actionUrl = QUrl(res["action"])
244 inputName = res["inputName"] 245 inputName = res["inputName"]
245 246
246 if method != "get": 247 if method != "get":
247 EricMessageBox.warning( 248 EricMessageBox.warning(
248 self, 249 self,
249 self.tr("Method not supported"), 250 self.tr("Method not supported"),
250 self.tr( 251 self.tr("""{0} method is not supported.""").format(method.upper()),
251 """{0} method is not supported.""").format(method.upper())) 252 )
252 return 253 return
253 254
254 if actionUrl.isRelative(): 255 if actionUrl.isRelative():
255 actionUrl = view.url().resolved(actionUrl) 256 actionUrl = view.url().resolved(actionUrl)
256 257
257 searchUrlQuery = QUrlQuery(actionUrl) 258 searchUrlQuery = QUrlQuery(actionUrl)
258 searchUrlQuery.addQueryItem(inputName, "{searchTerms}") 259 searchUrlQuery.addQueryItem(inputName, "{searchTerms}")
259 260
260 inputFields = res["inputs"] 261 inputFields = res["inputs"]
261 for inputField in inputFields: 262 for inputField in inputFields:
262 name = inputField[0] 263 name = inputField[0]
263 value = inputField[1] 264 value = inputField[1]
264 265
265 if not name or name == inputName or not value: 266 if not name or name == inputName or not value:
266 continue 267 continue
267 268
268 searchUrlQuery.addQueryItem(name, value) 269 searchUrlQuery.addQueryItem(name, value)
269 270
270 engineName, ok = QInputDialog.getText( 271 engineName, ok = QInputDialog.getText(
271 view, 272 view,
272 self.tr("Engine name"), 273 self.tr("Engine name"),
273 self.tr("Enter a name for the engine"), 274 self.tr("Enter a name for the engine"),
274 QLineEdit.EchoMode.Normal) 275 QLineEdit.EchoMode.Normal,
276 )
275 if not ok: 277 if not ok:
276 return 278 return
277 279
278 actionUrl.setQuery(searchUrlQuery) 280 actionUrl.setQuery(searchUrlQuery)
279 281
280 from .OpenSearchEngine import OpenSearchEngine 282 from .OpenSearchEngine import OpenSearchEngine
283
281 engine = OpenSearchEngine() 284 engine = OpenSearchEngine()
282 engine.setName(engineName) 285 engine.setName(engineName)
283 engine.setDescription(engineName) 286 engine.setDescription(engineName)
284 engine.setSearchUrlTemplate( 287 engine.setSearchUrlTemplate(
285 actionUrl.toDisplayString( 288 actionUrl.toDisplayString(QUrl.ComponentFormattingOption.FullyDecoded)
286 QUrl.ComponentFormattingOption.FullyDecoded)) 289 )
287 engine.setImage(view.icon().pixmap(16, 16).toImage()) 290 engine.setImage(view.icon().pixmap(16, 16).toImage())
288 291
289 self.__addEngineByEngine(engine) 292 self.__addEngineByEngine(engine)
290 293
291 def removeEngine(self, name): 294 def removeEngine(self, name):
292 """ 295 """
293 Public method to remove an engine. 296 Public method to remove an engine.
294 297
295 @param name name of the engine (string) 298 @param name name of the engine (string)
296 """ 299 """
297 if len(self.__engines) <= 1: 300 if len(self.__engines) <= 1:
298 return 301 return
299 302
300 if name not in self.__engines: 303 if name not in self.__engines:
301 return 304 return
302 305
303 engine = self.__engines[name] 306 engine = self.__engines[name]
304 for keyword in [k for k in self.__keywords 307 for keyword in [k for k in self.__keywords if self.__keywords[k] == engine]:
305 if self.__keywords[k] == engine]:
306 del self.__keywords[keyword] 308 del self.__keywords[keyword]
307 del self.__engines[name] 309 del self.__engines[name]
308 310
309 file_ = QDir(self.enginesDirectory()).filePath( 311 file_ = QDir(self.enginesDirectory()).filePath(
310 self.generateEngineFileName(name)) 312 self.generateEngineFileName(name)
313 )
311 os.unlink(file_) 314 os.unlink(file_)
312 315
313 if name == self.__current: 316 if name == self.__current:
314 self.setCurrentEngineName(list(self.__engines.keys())[0]) 317 self.setCurrentEngineName(list(self.__engines.keys())[0])
315 318
316 self.changed.emit() 319 self.changed.emit()
317 320
318 def generateEngineFileName(self, engineName): 321 def generateEngineFileName(self, engineName):
319 """ 322 """
320 Public method to generate a valid engine file name. 323 Public method to generate a valid engine file name.
321 324
322 @param engineName name of the engine (string) 325 @param engineName name of the engine (string)
323 @return valid engine file name (string) 326 @return valid engine file name (string)
324 """ 327 """
325 fileName = "" 328 fileName = ""
326 329
327 # strip special characters 330 # strip special characters
328 for c in engineName: 331 for c in engineName:
329 if c.isspace(): 332 if c.isspace():
330 fileName += '_' 333 fileName += "_"
331 continue 334 continue
332 335
333 if c.isalnum(): 336 if c.isalnum():
334 fileName += c 337 fileName += c
335 338
336 fileName += ".xml" 339 fileName += ".xml"
337 340
338 return fileName 341 return fileName
339 342
340 def saveDirectory(self, dirName): 343 def saveDirectory(self, dirName):
341 """ 344 """
342 Public method to save the search engine definitions to files. 345 Public method to save the search engine definitions to files.
343 346
344 @param dirName name of the directory to write the files to (string) 347 @param dirName name of the directory to write the files to (string)
345 """ 348 """
346 qdir = QDir() 349 qdir = QDir()
347 if not qdir.mkpath(dirName): 350 if not qdir.mkpath(dirName):
348 return 351 return
349 qdir.setPath(dirName) 352 qdir.setPath(dirName)
350 353
351 from .OpenSearchWriter import OpenSearchWriter 354 from .OpenSearchWriter import OpenSearchWriter
355
352 writer = OpenSearchWriter() 356 writer = OpenSearchWriter()
353 357
354 for engine in list(self.__engines.values()): 358 for engine in list(self.__engines.values()):
355 name = self.generateEngineFileName(engine.name()) 359 name = self.generateEngineFileName(engine.name())
356 fileName = qdir.filePath(name) 360 fileName = qdir.filePath(name)
357 361
358 file = QFile(fileName) 362 file = QFile(fileName)
359 if not file.open(QIODevice.OpenModeFlag.WriteOnly): 363 if not file.open(QIODevice.OpenModeFlag.WriteOnly):
360 continue 364 continue
361 365
362 writer.write(file, engine) 366 writer.write(file, engine)
363 367
364 def save(self): 368 def save(self):
365 """ 369 """
366 Public method to save the search engines configuration. 370 Public method to save the search engines configuration.
367 """ 371 """
368 if self.__loading: 372 if self.__loading:
369 return 373 return
370 374
371 self.saveDirectory(self.enginesDirectory()) 375 self.saveDirectory(self.enginesDirectory())
372 376
373 Preferences.setWebBrowser("WebSearchEngine", self.__current) 377 Preferences.setWebBrowser("WebSearchEngine", self.__current)
374 keywords = [] 378 keywords = []
375 for k in self.__keywords: 379 for k in self.__keywords:
376 if self.__keywords[k]: 380 if self.__keywords[k]:
377 keywords.append((k, self.__keywords[k].name())) 381 keywords.append((k, self.__keywords[k].name()))
378 Preferences.setWebBrowser("WebSearchKeywords", keywords) 382 Preferences.setWebBrowser("WebSearchKeywords", keywords)
379 383
380 def loadDirectory(self, dirName): 384 def loadDirectory(self, dirName):
381 """ 385 """
382 Public method to load the search engine definitions from files. 386 Public method to load the search engine definitions from files.
383 387
384 @param dirName name of the directory to load the files from (string) 388 @param dirName name of the directory to load the files from (string)
385 @return flag indicating success (boolean) 389 @return flag indicating success (boolean)
386 """ 390 """
387 if not os.path.exists(dirName): 391 if not os.path.exists(dirName):
388 return False 392 return False
389 393
390 success = False 394 success = False
391 395
392 qdir = QDir(dirName) 396 qdir = QDir(dirName)
393 for name in qdir.entryList(["*.xml"]): 397 for name in qdir.entryList(["*.xml"]):
394 fileName = qdir.filePath(name) 398 fileName = qdir.filePath(name)
395 if self.__addEngineByFile(fileName): 399 if self.__addEngineByFile(fileName):
396 success = True 400 success = True
397 401
398 return success 402 return success
399 403
400 def load(self): 404 def load(self):
401 """ 405 """
402 Public method to load the search engines configuration. 406 Public method to load the search engines configuration.
403 """ 407 """
404 self.__loading = True 408 self.__loading = True
405 self.__current = Preferences.getWebBrowser("WebSearchEngine") 409 self.__current = Preferences.getWebBrowser("WebSearchEngine")
406 keywords = Preferences.getWebBrowser("WebSearchKeywords") 410 keywords = Preferences.getWebBrowser("WebSearchKeywords")
407 411
408 if not self.loadDirectory(self.enginesDirectory()): 412 if not self.loadDirectory(self.enginesDirectory()):
409 self.restoreDefaults() 413 self.restoreDefaults()
410 414
411 for keyword, engineName in keywords: 415 for keyword, engineName in keywords:
412 self.__keywords[keyword] = self.engine(engineName) 416 self.__keywords[keyword] = self.engine(engineName)
413 417
414 if ( 418 if self.__current not in self.__engines and len(self.__engines) > 0:
415 self.__current not in self.__engines and
416 len(self.__engines) > 0
417 ):
418 self.__current = list(self.__engines.keys())[0] 419 self.__current = list(self.__engines.keys())[0]
419 420
420 self.__loading = False 421 self.__loading = False
421 self.currentEngineChanged.emit() 422 self.currentEngineChanged.emit()
422 423
423 def restoreDefaults(self): 424 def restoreDefaults(self):
424 """ 425 """
425 Public method to restore the default search engines. 426 Public method to restore the default search engines.
426 """ 427 """
427 from .OpenSearchReader import OpenSearchReader 428 from .OpenSearchReader import OpenSearchReader
428 429
429 reader = OpenSearchReader() 430 reader = OpenSearchReader()
430 defaultEnginesDirectory = os.path.join(os.path.dirname(__file__), 431 defaultEnginesDirectory = os.path.join(
431 "DefaultSearchEngines") 432 os.path.dirname(__file__), "DefaultSearchEngines"
432 for engineFileName in ( 433 )
433 QDir(defaultEnginesDirectory, "*.xml").entryList() 434 for engineFileName in QDir(defaultEnginesDirectory, "*.xml").entryList():
434 ): 435 engineFile = QFile(os.path.join(defaultEnginesDirectory, engineFileName))
435 engineFile = QFile(os.path.join(defaultEnginesDirectory,
436 engineFileName))
437 if not engineFile.open(QIODevice.OpenModeFlag.ReadOnly): 436 if not engineFile.open(QIODevice.OpenModeFlag.ReadOnly):
438 continue 437 continue
439 engine = reader.read(engineFile) 438 engine = reader.read(engineFile)
440 self.__addEngineByEngine(engine) 439 self.__addEngineByEngine(engine)
441 440
442 def enginesDirectory(self): 441 def enginesDirectory(self):
443 """ 442 """
444 Public method to determine the directory containing the search engine 443 Public method to determine the directory containing the search engine
445 descriptions. 444 descriptions.
446 445
447 @return directory name (string) 446 @return directory name (string)
448 """ 447 """
449 return os.path.join( 448 return os.path.join(Utilities.getConfigDir(), "web_browser", "searchengines")
450 Utilities.getConfigDir(), "web_browser", "searchengines") 449
451
452 def __confirmAddition(self, engine): 450 def __confirmAddition(self, engine):
453 """ 451 """
454 Private method to confirm the addition of a new search engine. 452 Private method to confirm the addition of a new search engine.
455 453
456 @param engine reference to the engine to be added (OpenSearchEngine) 454 @param engine reference to the engine to be added (OpenSearchEngine)
457 @return flag indicating the engine shall be added (boolean) 455 @return flag indicating the engine shall be added (boolean)
458 """ 456 """
459 if engine is None or not engine.isValid(): 457 if engine is None or not engine.isValid():
460 return False 458 return False
461 459
462 host = QUrl(engine.searchUrlTemplate()).host() 460 host = QUrl(engine.searchUrlTemplate()).host()
463 461
464 res = EricMessageBox.yesNo( 462 res = EricMessageBox.yesNo(
465 None, 463 None,
466 "", 464 "",
467 self.tr( 465 self.tr(
468 """<p>Do you want to add the following engine to your""" 466 """<p>Do you want to add the following engine to your"""
469 """ list of search engines?<br/><br/>Name: {0}<br/>""" 467 """ list of search engines?<br/><br/>Name: {0}<br/>"""
470 """Searches on: {1}</p>""").format(engine.name(), host)) 468 """Searches on: {1}</p>"""
469 ).format(engine.name(), host),
470 )
471 return res 471 return res
472 472
473 def __engineFromUrlAvailable(self, reply): 473 def __engineFromUrlAvailable(self, reply):
474 """ 474 """
475 Private slot to add a search engine from the net. 475 Private slot to add a search engine from the net.
476 476
477 @param reply reference to the network reply 477 @param reply reference to the network reply
478 @type QNetworkReply 478 @type QNetworkReply
479 """ 479 """
480 reply.close() 480 reply.close()
481 if reply in self.__replies: 481 if reply in self.__replies:
482 self.__replies.remove(reply) 482 self.__replies.remove(reply)
483 483
484 if reply.error() == QNetworkReply.NetworkError.NoError: 484 if reply.error() == QNetworkReply.NetworkError.NoError:
485 from .OpenSearchReader import OpenSearchReader 485 from .OpenSearchReader import OpenSearchReader
486
486 reader = OpenSearchReader() 487 reader = OpenSearchReader()
487 engine = reader.read(reply) 488 engine = reader.read(reply)
488 489
489 if not engine.isValid(): 490 if not engine.isValid():
490 return 491 return
491 492
492 if self.engineExists(engine.name()): 493 if self.engineExists(engine.name()):
493 return 494 return
494 495
495 if not self.__confirmAddition(engine): 496 if not self.__confirmAddition(engine):
496 return 497 return
497 498
498 if not self.__addEngineByEngine(engine): 499 if not self.__addEngineByEngine(engine):
499 return 500 return
500 else: 501 else:
501 # some error happened 502 # some error happened
502 from WebBrowser.WebBrowserWindow import WebBrowserWindow 503 from WebBrowser.WebBrowserWindow import WebBrowserWindow
504
503 WebBrowserWindow.getWindow().statusBar().showMessage( 505 WebBrowserWindow.getWindow().statusBar().showMessage(
504 reply.errorString(), 10000) 506 reply.errorString(), 10000
505 507 )
508
506 def convertKeywordSearchToUrl(self, keywordSearch): 509 def convertKeywordSearchToUrl(self, keywordSearch):
507 """ 510 """
508 Public method to get the search URL for a keyword search. 511 Public method to get the search URL for a keyword search.
509 512
510 @param keywordSearch search string for keyword search (string) 513 @param keywordSearch search string for keyword search (string)
511 @return search URL (QUrl) 514 @return search URL (QUrl)
512 """ 515 """
513 try: 516 try:
514 keyword, term = keywordSearch.split(" ", 1) 517 keyword, term = keywordSearch.split(" ", 1)
515 except ValueError: 518 except ValueError:
516 return QUrl() 519 return QUrl()
517 520
518 if not term: 521 if not term:
519 return QUrl() 522 return QUrl()
520 523
521 engine = self.engineForKeyword(keyword) 524 engine = self.engineForKeyword(keyword)
522 if engine: 525 if engine:
523 return engine.searchUrl(term) 526 return engine.searchUrl(term)
524 527
525 return QUrl() 528 return QUrl()
526 529
527 def engineForKeyword(self, keyword): 530 def engineForKeyword(self, keyword):
528 """ 531 """
529 Public method to get the engine for a keyword. 532 Public method to get the engine for a keyword.
530 533
531 @param keyword keyword to get engine for (string) 534 @param keyword keyword to get engine for (string)
532 @return reference to the search engine object (OpenSearchEngine) 535 @return reference to the search engine object (OpenSearchEngine)
533 """ 536 """
534 if keyword and keyword in self.__keywords: 537 if keyword and keyword in self.__keywords:
535 return self.__keywords[keyword] 538 return self.__keywords[keyword]
536 539
537 return None 540 return None
538 541
539 def setEngineForKeyword(self, keyword, engine): 542 def setEngineForKeyword(self, keyword, engine):
540 """ 543 """
541 Public method to set the engine for a keyword. 544 Public method to set the engine for a keyword.
542 545
543 @param keyword keyword to get engine for (string) 546 @param keyword keyword to get engine for (string)
544 @param engine reference to the search engine object (OpenSearchEngine) 547 @param engine reference to the search engine object (OpenSearchEngine)
545 or None to remove the keyword 548 or None to remove the keyword
546 """ 549 """
547 if not keyword: 550 if not keyword:
548 return 551 return
549 552
550 if engine is None: 553 if engine is None:
551 with contextlib.suppress(KeyError): 554 with contextlib.suppress(KeyError):
552 del self.__keywords[keyword] 555 del self.__keywords[keyword]
553 else: 556 else:
554 self.__keywords[keyword] = engine 557 self.__keywords[keyword] = engine
555 558
556 self.changed.emit() 559 self.changed.emit()
557 560
558 def keywordsForEngine(self, engine): 561 def keywordsForEngine(self, engine):
559 """ 562 """
560 Public method to get the keywords for a given engine. 563 Public method to get the keywords for a given engine.
561 564
562 @param engine reference to the search engine object (OpenSearchEngine) 565 @param engine reference to the search engine object (OpenSearchEngine)
563 @return list of keywords (list of strings) 566 @return list of keywords (list of strings)
564 """ 567 """
565 return [k for k in self.__keywords if self.__keywords[k] == engine] 568 return [k for k in self.__keywords if self.__keywords[k] == engine]
566 569
567 def setKeywordsForEngine(self, engine, keywords): 570 def setKeywordsForEngine(self, engine, keywords):
568 """ 571 """
569 Public method to set the keywords for an engine. 572 Public method to set the keywords for an engine.
570 573
571 @param engine reference to the search engine object (OpenSearchEngine) 574 @param engine reference to the search engine object (OpenSearchEngine)
572 @param keywords list of keywords (list of strings) 575 @param keywords list of keywords (list of strings)
573 """ 576 """
574 if engine is None: 577 if engine is None:
575 return 578 return
576 579
577 for keyword in self.keywordsForEngine(engine): 580 for keyword in self.keywordsForEngine(engine):
578 del self.__keywords[keyword] 581 del self.__keywords[keyword]
579 582
580 for keyword in keywords: 583 for keyword in keywords:
581 if not keyword: 584 if not keyword:
582 continue 585 continue
583 586
584 self.__keywords[keyword] = engine 587 self.__keywords[keyword] = engine
585 588
586 self.changed.emit() 589 self.changed.emit()
587 590
588 def enginesChanged(self): 591 def enginesChanged(self):
589 """ 592 """
590 Public slot to tell the search engine manager, that something has 593 Public slot to tell the search engine manager, that something has
591 changed. 594 changed.
592 """ 595 """

eric ide

mercurial