WebBrowser/WebBrowserView.py

branch
QtWebEngine
changeset 4711
0a9162801b8d
parent 4710
370a38e03efe
child 4713
8dca047daf4b
equal deleted inserted replaced
4710:370a38e03efe 4711:0a9162801b8d
3 # Copyright (c) 2008 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> 3 # Copyright (c) 2008 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 4 #
5 5
6 6
7 """ 7 """
8 Module implementing the helpbrowser using QWebView. 8 Module implementing the web browser using QWebEngineView.
9 """ 9 """
10 10
11 from __future__ import unicode_literals 11 from __future__ import unicode_literals
12 try: 12 try:
13 str = unicode 13 str = unicode
20 from PyQt5.QtGui import QDesktopServices, QClipboard, QMouseEvent, QColor, \ 20 from PyQt5.QtGui import QDesktopServices, QClipboard, QMouseEvent, QColor, \
21 QPalette 21 QPalette
22 from PyQt5.QtWidgets import qApp, QStyle, QMenu, QApplication, QInputDialog, \ 22 from PyQt5.QtWidgets import qApp, QStyle, QMenu, QApplication, QInputDialog, \
23 QLineEdit, QLabel, QToolTip, QFrame, QDialog 23 QLineEdit, QLabel, QToolTip, QFrame, QDialog
24 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog 24 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
25 from PyQt5.QtWebKit import QWebSettings
26 from PyQt5.QtWebKitWidgets import QWebView, QWebPage
27 try:
28 from PyQt5.QtWebKit import QWebElement
29 except ImportError:
30 pass
31 from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest 25 from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
32 import sip 26 from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
33 27
34 from E5Gui import E5MessageBox, E5FileDialog 28 from E5Gui import E5MessageBox, E5FileDialog
35 29
36 import Helpviewer 30 import WebBrowser
31 from .WebBrowserPage import WebBrowserPage
37 32
38 import Preferences 33 import Preferences
39 import UI.PixmapCache 34 import UI.PixmapCache
40 import Globals 35 import Globals
41 36
44 SSL_AVAILABLE = True 39 SSL_AVAILABLE = True
45 except ImportError: 40 except ImportError:
46 SSL_AVAILABLE = False 41 SSL_AVAILABLE = False
47 42
48 ############################################################################### 43 ###############################################################################
49 44 ##
50 45 ##
51 class JavaScriptExternalObject(QObject): 46 ##class JavaScriptExternalObject(QObject):
52 """ 47 ## """
53 Class implementing an external javascript object to add search providers. 48 ## Class implementing an external javascript object to add search providers.
54 """ 49 ## """
55 def __init__(self, mw, parent=None): 50 ## def __init__(self, mw, parent=None):
56 """ 51 ## """
57 Constructor 52 ## Constructor
58 53 ##
59 @param mw reference to the main window 8HelpWindow) 54 ## @param mw reference to the main window 8HelpWindow)
60 @param parent reference to the parent object (QObject) 55 ## @param parent reference to the parent object (QObject)
61 """ 56 ## """
62 super(JavaScriptExternalObject, self).__init__(parent) 57 ## super(JavaScriptExternalObject, self).__init__(parent)
63 58 ##
64 self.__mw = mw 59 ## self.__mw = mw
65 60 ##
66 @pyqtSlot(str) 61 ## @pyqtSlot(str)
67 def AddSearchProvider(self, url): 62 ## def AddSearchProvider(self, url):
68 """ 63 ## """
69 Public slot to add a search provider. 64 ## Public slot to add a search provider.
70 65 ##
71 @param url url of the XML file defining the search provider (string) 66 ## @param url url of the XML file defining the search provider (string)
72 """ 67 ## """
73 self.__mw.openSearchManager().addEngine(QUrl(url)) 68 ## self.__mw.openSearchManager().addEngine(QUrl(url))
74 69 ##
75 70 ##
76 class LinkedResource(object): 71 ##class LinkedResource(object):
77 """ 72 ## """
78 Class defining a data structure for linked resources. 73 ## Class defining a data structure for linked resources.
79 """ 74 ## """
80 def __init__(self): 75 ## def __init__(self):
81 """ 76 ## """
82 Constructor 77 ## Constructor
83 """ 78 ## """
84 self.rel = "" 79 ## self.rel = ""
85 self.type_ = "" 80 ## self.type_ = ""
86 self.href = "" 81 ## self.href = ""
87 self.title = "" 82 ## self.title = ""
88 83 ##
84 ###############################################################################
85 ##
86 ##
87 ##class JavaScriptEricObject(QObject):
88 ## """
89 ## Class implementing an external javascript object to search via the
90 ## startpage.
91 ## """
92 ## # these must be in line with the strings used by the javascript part of
93 ## # the start page
94 ## translations = [
95 ## QT_TRANSLATE_NOOP("JavaScriptEricObject",
96 ## "Welcome to eric6 Web Browser!"),
97 ## QT_TRANSLATE_NOOP("JavaScriptEricObject", "eric6 Web Browser"),
98 ## QT_TRANSLATE_NOOP("JavaScriptEricObject", "Search!"),
99 ## QT_TRANSLATE_NOOP("JavaScriptEricObject", "About eric6"),
100 ## ]
101 ##
102 ## def __init__(self, mw, parent=None):
103 ## """
104 ## Constructor
105 ##
106 ## @param mw reference to the main window 8HelpWindow)
107 ## @param parent reference to the parent object (QObject)
108 ## """
109 ## super(JavaScriptEricObject, self).__init__(parent)
110 ##
111 ## self.__mw = mw
112 ##
113 ## @pyqtSlot(str, result=str)
114 ## def translate(self, trans):
115 ## """
116 ## Public method to translate the given string.
117 ##
118 ## @param trans string to be translated (string)
119 ## @return translation (string)
120 ## """
121 ## if trans == "QT_LAYOUT_DIRECTION":
122 ## # special handling to detect layout direction
123 ## if qApp.isLeftToRight():
124 ## return "LTR"
125 ## else:
126 ## return "RTL"
127 ##
128 ## return self.tr(trans)
129 ##
130 ## @pyqtSlot(result=str)
131 ## def providerString(self):
132 ## """
133 ## Public method to get a string for the search provider.
134 ##
135 ## @return string for the search provider (string)
136 ## """
137 ## return self.tr("Search results provided by {0}")\
138 ## .format(self.__mw.openSearchManager().currentEngineName())
139 ##
140 ## @pyqtSlot(str, result=str)
141 ## def searchUrl(self, searchStr):
142 ## """
143 ## Public method to get the search URL for the given search term.
144 ##
145 ## @param searchStr search term (string)
146 ## @return search URL (string)
147 ## """
148 ## return bytes(
149 ## self.__mw.openSearchManager().currentEngine()
150 ## .searchUrl(searchStr).toEncoded()).decode()
151 ##
89 ############################################################################### 152 ###############################################################################
90 153
91 154
92 class JavaScriptEricObject(QObject): 155 class WebBrowserView(QWebEngineView):
93 """ 156 """
94 Class implementing an external javascript object to search via the 157 Class implementing the web browser view widget.
95 startpage.
96 """
97 # these must be in line with the strings used by the javascript part of
98 # the start page
99 translations = [
100 QT_TRANSLATE_NOOP("JavaScriptEricObject",
101 "Welcome to eric6 Web Browser!"),
102 QT_TRANSLATE_NOOP("JavaScriptEricObject", "eric6 Web Browser"),
103 QT_TRANSLATE_NOOP("JavaScriptEricObject", "Search!"),
104 QT_TRANSLATE_NOOP("JavaScriptEricObject", "About eric6"),
105 ]
106
107 def __init__(self, mw, parent=None):
108 """
109 Constructor
110
111 @param mw reference to the main window 8HelpWindow)
112 @param parent reference to the parent object (QObject)
113 """
114 super(JavaScriptEricObject, self).__init__(parent)
115
116 self.__mw = mw
117
118 @pyqtSlot(str, result=str)
119 def translate(self, trans):
120 """
121 Public method to translate the given string.
122
123 @param trans string to be translated (string)
124 @return translation (string)
125 """
126 if trans == "QT_LAYOUT_DIRECTION":
127 # special handling to detect layout direction
128 if qApp.isLeftToRight():
129 return "LTR"
130 else:
131 return "RTL"
132
133 return self.tr(trans)
134
135 @pyqtSlot(result=str)
136 def providerString(self):
137 """
138 Public method to get a string for the search provider.
139
140 @return string for the search provider (string)
141 """
142 return self.tr("Search results provided by {0}")\
143 .format(self.__mw.openSearchManager().currentEngineName())
144
145 @pyqtSlot(str, result=str)
146 def searchUrl(self, searchStr):
147 """
148 Public method to get the search URL for the given search term.
149
150 @param searchStr search term (string)
151 @return search URL (string)
152 """
153 return bytes(
154 self.__mw.openSearchManager().currentEngine()
155 .searchUrl(searchStr).toEncoded()).decode()
156
157 ###############################################################################
158
159
160 class HelpWebPage(QWebPage):
161 """
162 Class implementing an enhanced web page.
163 """
164 _webPluginFactory = None
165
166 def __init__(self, parent=None):
167 """
168 Constructor
169
170 @param parent parent widget of this window (QWidget)
171 """
172 super(HelpWebPage, self).__init__(parent)
173
174 self.setPluginFactory(self.webPluginFactory())
175
176 self.__lastRequest = None
177 self.__lastRequestType = QWebPage.NavigationTypeOther
178
179 import Helpviewer.HelpWindow
180 from .Network.NetworkAccessManagerProxy import \
181 NetworkAccessManagerProxy
182 self.__proxy = NetworkAccessManagerProxy(self)
183 self.__proxy.setWebPage(self)
184 self.__proxy.setPrimaryNetworkAccessManager(
185 Helpviewer.HelpWindow.HelpWindow.networkAccessManager())
186 self.setNetworkAccessManager(self.__proxy)
187
188 self.__sslConfiguration = None
189 self.__proxy.finished.connect(self.__managerFinished)
190
191 self.__adBlockedEntries = []
192 self.loadStarted.connect(self.__loadStarted)
193
194 self.saveFrameStateRequested.connect(
195 self.__saveFrameStateRequested)
196 self.restoreFrameStateRequested.connect(
197 self.__restoreFrameStateRequested)
198
199 def acceptNavigationRequest(self, frame, request, type_):
200 """
201 Public method to determine, if a request may be accepted.
202
203 @param frame reference to the frame sending the request (QWebFrame)
204 @param request reference to the request object (QNetworkRequest)
205 @param type_ type of the navigation request (QWebPage.NavigationType)
206 @return flag indicating acceptance (boolean)
207 """
208 self.__lastRequest = request
209 if self.__lastRequest.url() != request.url() or \
210 type_ != QWebPage.NavigationTypeOther:
211 self.__lastRequestType = type_
212
213 scheme = request.url().scheme()
214 if scheme == "mailto":
215 QDesktopServices.openUrl(request.url())
216 return False
217
218 if type_ == QWebPage.NavigationTypeFormResubmitted:
219 res = E5MessageBox.yesNo(
220 self.view(),
221 self.tr("Resending POST request"),
222 self.tr(
223 """In order to display the site, the request along with"""
224 """ all the data must be sent once again, which may lead"""
225 """ to some unexpected behaviour of the site e.g. the"""
226 """ same action might be performed once again. Do you"""
227 """ want to continue anyway?"""),
228 icon=E5MessageBox.Warning)
229 if not res:
230 return False
231
232 return QWebPage.acceptNavigationRequest(self, frame, request, type_)
233
234 def populateNetworkRequest(self, request):
235 """
236 Public method to add data to a network request.
237
238 @param request reference to the network request object
239 (QNetworkRequest)
240 """
241 try:
242 request.setAttribute(QNetworkRequest.User + 100, self)
243 if self.__lastRequest.url() == request.url():
244 request.setAttribute(QNetworkRequest.User + 101,
245 self.__lastRequestType)
246 if self.__lastRequestType == \
247 QWebPage.NavigationTypeLinkClicked:
248 request.setRawHeader(b"X-Eric6-UserLoadAction",
249 QByteArray(b"1"))
250 except TypeError:
251 pass
252
253 def pageAttributeId(self):
254 """
255 Public method to get the attribute id of the page attribute.
256
257 @return attribute id of the page attribute (integer)
258 """
259 return QNetworkRequest.User + 100
260
261 def supportsExtension(self, extension):
262 """
263 Public method to check the support for an extension.
264
265 @param extension extension to test for (QWebPage.Extension)
266 @return flag indicating the support of extension (boolean)
267 """
268 try:
269 if extension in [QWebPage.ErrorPageExtension,
270 QWebPage.ChooseMultipleFilesExtension]:
271 return True
272 except AttributeError:
273 pass
274
275 return QWebPage.supportsExtension(self, extension)
276
277 def extension(self, extension, option, output):
278 """
279 Public method to implement a specific extension.
280
281 @param extension extension to be executed (QWebPage.Extension)
282 @param option provides input to the extension
283 (QWebPage.ExtensionOption)
284 @param output stores the output results (QWebPage.ExtensionReturn)
285 @return flag indicating a successful call of the extension (boolean)
286 """
287 if extension == QWebPage.ChooseMultipleFilesExtension:
288 info = sip.cast(option,
289 QWebPage.ChooseMultipleFilesExtensionOption)
290 files = sip.cast(output,
291 QWebPage.ChooseMultipleFilesExtensionReturn)
292 if info is None or files is None:
293 return super(HelpWebPage, self).extension(
294 extension, option, output)
295
296 suggestedFileName = ""
297 if info.suggestedFileNames:
298 suggestedFileName = info.suggestedFileNames[0]
299
300 files.fileNames = E5FileDialog.getOpenFileNames(
301 None,
302 self.tr("Select files to upload..."),
303 suggestedFileName)
304 return True
305
306 if extension == QWebPage.ErrorPageExtension:
307 info = sip.cast(option, QWebPage.ErrorPageExtensionOption)
308
309 errorPage = sip.cast(output, QWebPage.ErrorPageExtensionReturn)
310 urlString = bytes(info.url.toEncoded()).decode()
311 errorPage.baseUrl = info.url
312 if info.domain == QWebPage.QtNetwork and \
313 info.error == QNetworkReply.ProtocolUnknownError:
314 url = QUrl(info.url)
315 res = E5MessageBox.yesNo(
316 None,
317 self.tr("Protocol Error"),
318 self.tr("""Open external application for {0}-link?\n"""
319 """URL: {1}""").format(
320 url.scheme(), url.toString(
321 QUrl.PrettyDecoded | QUrl.RemovePassword)),
322 yesDefault=True)
323
324 if res:
325 QDesktopServices.openUrl(url)
326 return True
327 elif info.domain == QWebPage.QtNetwork and \
328 info.error == QNetworkReply.ContentAccessDenied and \
329 info.errorString.startswith("AdBlockRule:"):
330 if info.frame != info.frame.page().mainFrame():
331 # content in <iframe>
332 docElement = info.frame.page().mainFrame()\
333 .documentElement()
334 for element in docElement.findAll("iframe"):
335 src = element.attribute("src")
336 if src in info.url.toString():
337 element.setAttribute("style", "display:none;")
338 return False
339 else:
340 # the whole page is blocked
341 rule = info.errorString.replace("AdBlockRule:", "")
342 title = self.tr("Content blocked by AdBlock Plus")
343 message = self.tr(
344 "Blocked by rule: <i>{0}</i>").format(rule)
345
346 htmlFile = QFile(":/html/adblockPage.html")
347 htmlFile.open(QFile.ReadOnly)
348 html = htmlFile.readAll()
349 html = html.replace(
350 "@FAVICON@", "qrc:icons/adBlockPlus16.png")
351 html = html.replace(
352 "@IMAGE@", "qrc:icons/adBlockPlus64.png")
353 html = html.replace("@TITLE@", title.encode("utf8"))
354 html = html.replace("@MESSAGE@", message.encode("utf8"))
355 errorPage.content = html
356 return True
357
358 if info.domain == QWebPage.QtNetwork and \
359 info.error == QNetworkReply.OperationCanceledError and \
360 info.errorString == "eric6:No Error":
361 return False
362
363 if info.domain == QWebPage.WebKit and info.error == 203:
364 # "Loading is handled by the media engine"
365 return False
366
367 title = self.tr("Error loading page: {0}").format(urlString)
368 htmlFile = QFile(":/html/notFoundPage.html")
369 htmlFile.open(QFile.ReadOnly)
370 html = htmlFile.readAll()
371 pixmap = qApp.style()\
372 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48)
373 imageBuffer = QBuffer()
374 imageBuffer.open(QIODevice.ReadWrite)
375 if pixmap.save(imageBuffer, "PNG"):
376 html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64())
377 pixmap = qApp.style()\
378 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16)
379 imageBuffer = QBuffer()
380 imageBuffer.open(QIODevice.ReadWrite)
381 if pixmap.save(imageBuffer, "PNG"):
382 html = html.replace(
383 "@FAVICON@", imageBuffer.buffer().toBase64())
384 html = html.replace("@TITLE@", title.encode("utf8"))
385 html = html.replace("@H1@", info.errorString.encode("utf8"))
386 html = html.replace(
387 "@H2@", self.tr("When connecting to: {0}.")
388 .format(urlString).encode("utf8"))
389 html = html.replace(
390 "@LI-1@",
391 self.tr("Check the address for errors such as "
392 "<b>ww</b>.example.org instead of "
393 "<b>www</b>.example.org").encode("utf8"))
394 html = html.replace(
395 "@LI-2@",
396 self.tr(
397 "If the address is correct, try checking the network "
398 "connection.").encode("utf8"))
399 html = html.replace(
400 "@LI-3@",
401 self.tr(
402 "If your computer or network is protected by a firewall "
403 "or proxy, make sure that the browser is permitted to "
404 "access the network.").encode("utf8"))
405 html = html.replace(
406 "@LI-4@",
407 self.tr("If your cache policy is set to offline browsing,"
408 "only pages in the local cache are available.")
409 .encode("utf8"))
410 html = html.replace(
411 "@BUTTON@", self.tr("Try Again").encode("utf8"))
412 errorPage.content = html
413 return True
414
415 return QWebPage.extension(self, extension, option, output)
416
417 def __loadStarted(self):
418 """
419 Private method to handle the loadStarted signal.
420 """
421 self.__adBlockedEntries = []
422
423 def addAdBlockRule(self, rule, url):
424 """
425 Public slot to add an AdBlock rule to the page.
426
427 @param rule AdBlock rule to add (AdBlockRule)
428 @param url URL that matched the rule (QUrl)
429 """
430 from .AdBlock.AdBlockPage import AdBlockedPageEntry
431 entry = AdBlockedPageEntry(rule, url)
432 if entry not in self.__adBlockedEntries:
433 self.__adBlockedEntries.append(entry)
434
435 def getAdBlockedPageEntries(self):
436 """
437 Public method to get the list of AdBlock page entries.
438
439 @return list of AdBlock page entries (list of AdBlockedPageEntry)
440 """
441 return self.__adBlockedEntries
442
443 def url(self):
444 """
445 Public method to get the URL of the page.
446
447 @return URL of the page (QUrl)
448 """
449 return self.mainFrame().url()
450
451 def userAgent(self, resolveEmpty=False):
452 """
453 Public method to get the global user agent setting.
454
455 @param resolveEmpty flag indicating to resolve an empty
456 user agent (boolean)
457 @return user agent string (string)
458 """
459 agent = Preferences.getHelp("UserAgent")
460 if agent == "" and resolveEmpty:
461 agent = self.userAgentForUrl(QUrl())
462 return agent
463
464 def setUserAgent(self, agent):
465 """
466 Public method to set the global user agent string.
467
468 @param agent new current user agent string (string)
469 """
470 Preferences.setHelp("UserAgent", agent)
471
472 def userAgentForUrl(self, url):
473 """
474 Public method to determine the user agent for the given URL.
475
476 @param url URL to determine user agent for (QUrl)
477 @return user agent string (string)
478 """
479 import Helpviewer.HelpWindow
480 agent = Helpviewer.HelpWindow.HelpWindow.userAgentsManager()\
481 .userAgentForUrl(url)
482 if agent == "":
483 # no agent string specified for the given host -> use global one
484 agent = Preferences.getHelp("UserAgent")
485 if agent == "":
486 # no global agent string specified -> use default one
487 agent = QWebPage.userAgentForUrl(self, url)
488 return agent
489
490 def __managerFinished(self, reply):
491 """
492 Private slot to handle a finished reply.
493
494 This slot is used to get SSL related information for a reply.
495
496 @param reply reference to the finished reply (QNetworkReply)
497 """
498 try:
499 frame = reply.request().originatingObject()
500 except AttributeError:
501 frame = None
502
503 mainFrameRequest = frame == self.mainFrame()
504
505 if mainFrameRequest and \
506 self.__sslConfiguration is not None and \
507 reply.url() == self.mainFrame().url():
508 self.__sslConfiguration = None
509
510 if reply.error() == QNetworkReply.NoError and \
511 mainFrameRequest and \
512 self.__sslConfiguration is None and \
513 reply.url().scheme().lower() == "https" and \
514 reply.url() == self.mainFrame().url():
515 self.__sslConfiguration = reply.sslConfiguration()
516 self.__sslConfiguration.url = QUrl(reply.url())
517
518 if reply.error() == QNetworkReply.NoError and \
519 mainFrameRequest and \
520 reply.url() == self.mainFrame().url():
521 modified = reply.header(QNetworkRequest.LastModifiedHeader)
522 if modified and modified.isValid():
523 import Helpviewer.HelpWindow
524 manager = Helpviewer.HelpWindow.HelpWindow.bookmarksManager()
525 from .Bookmarks.BookmarkNode import BookmarkNode
526 for bookmark in manager.bookmarksForUrl(reply.url()):
527 manager.setTimestamp(bookmark, BookmarkNode.TsModified,
528 modified)
529
530 def getSslCertificate(self):
531 """
532 Public method to get a reference to the SSL certificate.
533
534 @return amended SSL certificate (QSslCertificate)
535 """
536 if self.__sslConfiguration is None:
537 return None
538
539 sslInfo = self.__sslConfiguration.peerCertificate()
540 sslInfo.url = QUrl(self.__sslConfiguration.url)
541 return sslInfo
542
543 def getSslCertificateChain(self):
544 """
545 Public method to get a reference to the SSL certificate chain.
546
547 @return SSL certificate chain (list of QSslCertificate)
548 """
549 if self.__sslConfiguration is None:
550 return []
551
552 chain = self.__sslConfiguration.peerCertificateChain()
553 return chain
554
555 def getSslConfiguration(self):
556 """
557 Public method to return a reference to the current SSL configuration.
558
559 @return reference to the SSL configuration in use (QSslConfiguration)
560 """
561 return self.__sslConfiguration
562
563 def showSslInfo(self, pos):
564 """
565 Public slot to show some SSL information for the loaded page.
566
567 @param pos position to show the info at (QPoint)
568 """
569 if SSL_AVAILABLE and self.__sslConfiguration is not None:
570 from E5Network.E5SslInfoWidget import E5SslInfoWidget
571 widget = E5SslInfoWidget(
572 self.mainFrame().url(), self.__sslConfiguration, self.view())
573 widget.showAt(pos)
574 else:
575 E5MessageBox.warning(
576 self.view(),
577 self.tr("SSL Info"),
578 self.tr("""This site does not contain SSL information."""))
579
580 def hasValidSslInfo(self):
581 """
582 Public method to check, if the page has a valid SSL certificate.
583
584 @return flag indicating a valid SSL certificate (boolean)
585 """
586 if self.__sslConfiguration is None:
587 return False
588
589 certList = self.__sslConfiguration.peerCertificateChain()
590 if not certList:
591 return False
592
593 certificateDict = Globals.toDict(
594 Preferences.Prefs.settings.value("Ssl/CaCertificatesDict"))
595 for server in certificateDict:
596 localCAList = QSslCertificate.fromData(certificateDict[server])
597 for cert in certList:
598 if cert in localCAList:
599 return True
600
601 if qVersion() >= "5.0.0":
602 for cert in certList:
603 if cert.isBlacklisted():
604 return False
605 else:
606 for cert in certList:
607 if not cert.isValid():
608 return False
609
610 return True
611
612 @classmethod
613 def webPluginFactory(cls):
614 """
615 Class method to get a reference to the web plug-in factory
616 instance.
617
618 @return reference to the web plug-in factory instance (WebPluginFactory
619 """
620 if cls._webPluginFactory is None:
621 from .WebPlugins.WebPluginFactory import WebPluginFactory
622 cls._webPluginFactory = WebPluginFactory()
623
624 return cls._webPluginFactory
625
626 def event(self, evt):
627 """
628 Public method implementing the event handler.
629
630 @param evt reference to the event (QEvent)
631 @return flag indicating that the event was handled (boolean)
632 """
633 if evt.type() == QEvent.Leave:
634 # Fake a mouse move event just outside of the widget to trigger
635 # the WebKit event handler's mouseMoved function. This implements
636 # the interesting mouse-out behavior like invalidating scrollbars.
637 fakeEvent = QMouseEvent(QEvent.MouseMove, QPoint(0, -1),
638 Qt.NoButton, Qt.NoButton, Qt.NoModifier)
639 return super(HelpWebPage, self).event(fakeEvent)
640
641 return super(HelpWebPage, self).event(evt)
642
643 def __saveFrameStateRequested(self, frame, itm):
644 """
645 Private slot to save the page state (i.e. zoom level and scroll
646 position).
647
648 Note: Code is based on qutebrowser.
649
650 @param frame frame to be saved
651 @type QWebFrame
652 @param itm web history item to be saved
653 @type QWebHistoryItem
654 """
655 try:
656 if frame != self.mainFrame():
657 return
658 except RuntimeError:
659 # With Qt 5.2.1 (Ubuntu Trusty) we get this when closing a tab:
660 # RuntimeError: wrapped C/C++ object of type BrowserPage has
661 # been deleted
662 # Since the information here isn't that important for closing web
663 # views anyways, we ignore this error.
664 return
665 data = {
666 'zoom': frame.zoomFactor(),
667 'scrollPos': frame.scrollPosition(),
668 }
669 itm.setUserData(data)
670
671 def __restoreFrameStateRequested(self, frame):
672 """
673 Private slot to restore scroll position and zoom level from
674 history.
675
676 Note: Code is based on qutebrowser.
677
678 @param frame frame to be restored
679 @type QWebFrame
680 """
681 if frame != self.mainFrame():
682 return
683
684 data = self.history().currentItem().userData()
685 if data is None:
686 return
687
688 if 'zoom' in data:
689 frame.page().view().setZoomValue(int(data['zoom'] * 100),
690 saveValue=False)
691
692 if 'scrollPos' in data and frame.scrollPosition() == QPoint(0, 0):
693 frame.setScrollPosition(data['scrollPos'])
694
695 ###############################################################################
696
697
698 class HelpBrowser(QWebView):
699 """
700 Class implementing the helpbrowser widget.
701
702 This is a subclass of the Qt QWebView to implement an
703 interface compatible with the QTextBrowser based variant.
704 158
705 @signal sourceChanged(QUrl) emitted after the current URL has changed 159 @signal sourceChanged(QUrl) emitted after the current URL has changed
706 @signal forwardAvailable(bool) emitted after the current URL has changed 160 @signal forwardAvailable(bool) emitted after the current URL has changed
707 @signal backwardAvailable(bool) emitted after the current URL has changed 161 @signal backwardAvailable(bool) emitted after the current URL has changed
708 @signal highlighted(str) emitted, when the mouse hovers over a link 162 @signal highlighted(str) emitted, when the mouse hovers over a link
715 highlighted = pyqtSignal(str) 169 highlighted = pyqtSignal(str)
716 search = pyqtSignal(QUrl) 170 search = pyqtSignal(QUrl)
717 zoomValueChanged = pyqtSignal(int) 171 zoomValueChanged = pyqtSignal(int)
718 172
719 ZoomLevels = [ 173 ZoomLevels = [
720 30, 50, 67, 80, 90, 174 30, 40, 50, 67, 80, 90,
721 100, 175 100,
722 110, 120, 133, 150, 170, 200, 240, 300, 176 110, 120, 133, 150, 170, 200, 220, 233, 250, 270, 285, 300,
723 ] 177 ]
724 ZoomLevelDefault = 100 178 ZoomLevelDefault = 100
725 179
726 def __init__(self, mainWindow, parent=None, name=""): 180 def __init__(self, mainWindow, parent=None, name=""):
727 """ 181 """
728 Constructor 182 Constructor
729 183
730 @param mainWindow reference to the main window (HelpWindow) 184 @param mainWindow reference to the main window (WebBrowserWindow)
731 @param parent parent widget of this window (QWidget) 185 @param parent parent widget of this window (QWidget)
732 @param name name of this window (string) 186 @param name name of this window (string)
733 """ 187 """
734 super(HelpBrowser, self).__init__(parent) 188 super(WebBrowserView, self).__init__(parent)
735 self.setObjectName(name) 189 self.setObjectName(name)
736 self.setWhatsThis(self.tr( 190 ##
737 """<b>Help Window</b>""" 191 ## import Helpviewer.HelpWindow
738 """<p>This window displays the selected help information.</p>""" 192 ## self.__speedDial = Helpviewer.HelpWindow.HelpWindow.speedDial()
739 )) 193
740 194 self.__page = WebBrowserPage(self)
741 import Helpviewer.HelpWindow
742 self.__speedDial = Helpviewer.HelpWindow.HelpWindow.speedDial()
743
744 self.__page = HelpWebPage(self)
745 self.setPage(self.__page) 195 self.setPage(self.__page)
746 196
747 self.mw = mainWindow 197 self.__mw = mainWindow
748 self.ctrlPressed = False 198 self.__ctrlPressed = False
749 self.__isLoading = False 199 self.__isLoading = False
750 self.__progress = 0 200 self.__progress = 0
751 201
752 self.__currentZoom = 100 202 self.__currentZoom = 100
753 self.__zoomLevels = HelpBrowser.ZoomLevels[:] 203 self.__zoomLevels = WebBrowserView.ZoomLevels[:]
754 204 ##
755 self.__javaScriptBinding = None 205 ## self.__javaScriptBinding = None
756 self.__javaScriptEricObject = None 206 ## self.__javaScriptEricObject = None
757 207
758 self.mw.zoomTextOnlyChanged.connect(self.__applyZoom) 208 ## self.__mw.zoomTextOnlyChanged.connect(self.__applyZoom)
759 209
760 self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) 210 ## self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
761 self.linkClicked.connect(self.setSource) 211 ## self.linkClicked.connect(self.setSource)
762 212 ##
763 self.urlChanged.connect(self.__urlChanged) 213 self.urlChanged.connect(self.__urlChanged)
764 self.statusBarMessage.connect(self.__statusBarMessage) 214 ## self.statusBarMessage.connect(self.__statusBarMessage)
765 self.page().linkHovered.connect(self.__linkHovered) 215 self.page().linkHovered.connect(self.__linkHovered)
766 216
767 self.loadStarted.connect(self.__loadStarted) 217 self.loadStarted.connect(self.__loadStarted)
768 self.loadProgress.connect(self.__loadProgress) 218 self.loadProgress.connect(self.__loadProgress)
769 self.loadFinished.connect(self.__loadFinished) 219 self.loadFinished.connect(self.__loadFinished)
770 220
771 self.page().setForwardUnsupportedContent(True) 221 ## self.page().setForwardUnsupportedContent(True)
772 self.page().unsupportedContent.connect(self.__unsupportedContent) 222 ## self.page().unsupportedContent.connect(self.__unsupportedContent)
773 223
774 self.page().featurePermissionRequested.connect( 224 # TODO: this was moved to QWebEngineProfile
775 self.__featurePermissionRequested) 225 ## self.page().downloadRequested.connect(self.__downloadRequested)
776 226 ## self.page().frameCreated.connect(self.__addExternalBinding)
777 self.page().downloadRequested.connect(self.__downloadRequested) 227 ## self.__addExternalBinding(self.page().mainFrame())
778 self.page().frameCreated.connect(self.__addExternalBinding) 228
779 self.__addExternalBinding(self.page().mainFrame()) 229 ## self.page().databaseQuotaExceeded.connect(self.__databaseQuotaExceeded)
780 230
781 self.page().databaseQuotaExceeded.connect(self.__databaseQuotaExceeded) 231 # TODO: re-enable onece Open Search is done
782 232 ## self.__mw.openSearchManager().currentEngineChanged.connect(
783 self.mw.openSearchManager().currentEngineChanged.connect( 233 ## self.__currentEngineChanged)
784 self.__currentEngineChanged)
785 234
786 self.setAcceptDrops(True) 235 self.setAcceptDrops(True)
787 236
788 self.__enableAccessKeys = Preferences.getHelp("AccessKeysEnabled") 237 # TODO: re-enable for Access Keys
789 self.__accessKeysPressed = False 238 ## self.__enableAccessKeys = Preferences.getHelp("AccessKeysEnabled")
790 self.__accessKeyLabels = [] 239 ## self.__accessKeysPressed = False
791 self.__accessKeyNodes = {} 240 ## self.__accessKeyLabels = []
792 241 ## self.__accessKeyNodes = {}
793 self.page().loadStarted.connect(self.__hideAccessKeys) 242 ##
794 self.page().scrollRequested.connect(self.__hideAccessKeys) 243 ## self.page().loadStarted.connect(self.__hideAccessKeys)
244 ## self.page().scrollRequested.connect(self.__hideAccessKeys)
795 245
796 self.__rss = [] 246 self.__rss = []
797 247
798 self.__clickedFrame = None 248 self.__clickedFrame = None
799 249
800 self.mw.personalInformationManager().connectPage(self.page()) 250 # TODO: re-enable once done
801 self.mw.greaseMonkeyManager().connectPage(self.page()) 251 ## self.__mw.personalInformationManager().connectPage(self.page())
802 252 ## self.__mw.greaseMonkeyManager().connectPage(self.page())
803 self.__inspector = None 253 ##
254 ## self.__inspector = None
804 255
805 self.grabGesture(Qt.PinchGesture) 256 self.grabGesture(Qt.PinchGesture)
806 257
807 def __addExternalBinding(self, frame=None): 258 ## def __addExternalBinding(self, frame=None):
808 """ 259 ## """
809 Private slot to add javascript bindings for adding search providers. 260 ## Private slot to add javascript bindings for adding search providers.
810 261 ##
811 @param frame reference to the web frame (QWebFrame) 262 ## @param frame reference to the web frame (QWebFrame)
812 """ 263 ## """
813 self.page().settings().setAttribute(QWebSettings.JavascriptEnabled, 264 ## self.page().settings().setAttribute(QWebSettings.JavascriptEnabled,
814 True) 265 ## True)
815 if self.__javaScriptBinding is None: 266 ## if self.__javaScriptBinding is None:
816 self.__javaScriptBinding = JavaScriptExternalObject(self.mw, self) 267 ## self.__javaScriptBinding = JavaScriptExternalObject(self.__mw, self)
817 268 ##
818 if frame is None: 269 ## if frame is None:
819 # called from QWebFrame.javaScriptWindowObjectCleared 270 ## # called from QWebFrame.javaScriptWindowObjectCleared
820 frame = self.sender() 271 ## frame = self.sender()
821 if isinstance(frame, HelpWebPage): 272 ## if isinstance(frame, HelpWebPage):
822 frame = frame.mainFrame() 273 ## frame = frame.mainFrame()
823 if frame.url().scheme() == "eric" and frame.url().path() == "home": 274 ## if frame.url().scheme() == "eric" and frame.url().path() == "home":
824 if self.__javaScriptEricObject is None: 275 ## if self.__javaScriptEricObject is None:
825 self.__javaScriptEricObject = JavaScriptEricObject( 276 ## self.__javaScriptEricObject = JavaScriptEricObject(
826 self.mw, self) 277 ## self.__mw, self)
827 frame.addToJavaScriptWindowObject( 278 ## frame.addToJavaScriptWindowObject(
828 "eric", self.__javaScriptEricObject) 279 ## "eric", self.__javaScriptEricObject)
829 elif frame.url().scheme() == "eric" and \ 280 ## elif frame.url().scheme() == "eric" and \
830 frame.url().path() == "speeddial": 281 ## frame.url().path() == "speeddial":
831 frame.addToJavaScriptWindowObject( 282 ## frame.addToJavaScriptWindowObject(
832 "speeddial", self.__speedDial) 283 ## "speeddial", self.__speedDial)
833 self.__speedDial.addWebFrame(frame) 284 ## self.__speedDial.addWebFrame(frame)
834 else: 285 ## else:
835 # called from QWebPage.frameCreated 286 ## # called from QWebPage.frameCreated
836 frame.javaScriptWindowObjectCleared.connect( 287 ## frame.javaScriptWindowObjectCleared.connect(
837 self.__addExternalBinding) 288 ## self.__addExternalBinding)
838 frame.addToJavaScriptWindowObject("external", self.__javaScriptBinding) 289 ## frame.addToJavaScriptWindowObject("external", self.__javaScriptBinding)
839 290 ##
840 def linkedResources(self, relation=""): 291 ## def linkedResources(self, relation=""):
841 """ 292 ## """
842 Public method to extract linked resources. 293 ## Public method to extract linked resources.
843 294 ##
844 @param relation relation to extract (string) 295 ## @param relation relation to extract (string)
845 @return list of linked resources (list of LinkedResource) 296 ## @return list of linked resources (list of LinkedResource)
846 """ 297 ## """
847 resources = [] 298 ## resources = []
848 299 ##
849 baseUrl = self.page().mainFrame().baseUrl() 300 ## baseUrl = self.page().mainFrame().baseUrl()
850 301 ##
851 linkElements = self.page().mainFrame().findAllElements( 302 ## linkElements = self.page().mainFrame().findAllElements(
852 "html > head > link") 303 ## "html > head > link")
853 304 ##
854 for linkElement in linkElements.toList(): 305 ## for linkElement in linkElements.toList():
855 rel = linkElement.attribute("rel") 306 ## rel = linkElement.attribute("rel")
856 href = linkElement.attribute("href") 307 ## href = linkElement.attribute("href")
857 type_ = linkElement.attribute("type") 308 ## type_ = linkElement.attribute("type")
858 title = linkElement.attribute("title") 309 ## title = linkElement.attribute("title")
859 310 ##
860 if href == "" or type_ == "": 311 ## if href == "" or type_ == "":
861 continue 312 ## continue
862 if relation and rel != relation: 313 ## if relation and rel != relation:
863 continue 314 ## continue
864 315 ##
865 resource = LinkedResource() 316 ## resource = LinkedResource()
866 resource.rel = rel 317 ## resource.rel = rel
867 resource.type_ = type_ 318 ## resource.type_ = type_
868 resource.href = baseUrl.resolved( 319 ## resource.href = baseUrl.resolved(
869 QUrl.fromEncoded(href.encode("utf-8"))) 320 ## QUrl.fromEncoded(href.encode("utf-8")))
870 resource.title = title 321 ## resource.title = title
871 322 ##
872 resources.append(resource) 323 ## resources.append(resource)
873 324 ##
874 return resources 325 ## return resources
875 326 ##
876 def __currentEngineChanged(self): 327 ## def __currentEngineChanged(self):
877 """ 328 ## """
878 Private slot to track a change of the current search engine. 329 ## Private slot to track a change of the current search engine.
879 """ 330 ## """
880 if self.url().toString() == "eric:home": 331 ## if self.url().toString() == "eric:home":
881 self.reload() 332 ## self.reload()
882 333
334 # TODO: eliminate requestData
883 def setSource(self, name, requestData=None): 335 def setSource(self, name, requestData=None):
884 """ 336 """
885 Public method used to set the source to be displayed. 337 Public method used to set the source to be displayed.
886 338
887 @param name filename to be shown (QUrl) 339 @param name filename to be shown (QUrl)
888 @param requestData tuple containing the request data (QNetworkRequest, 340 @param requestData tuple containing the request data (QNetworkRequest,
889 QNetworkAccessManager.Operation, QByteArray) 341 QNetworkAccessManager.Operation, QByteArray)
890 """ 342 """
891 if (name is None or not name.isValid()) and requestData is None: 343 ## if (name is None or not name.isValid()) and requestData is None:
344 if name is None or not name.isValid():
892 return 345 return
893 346
894 if name is None and requestData is not None: 347 ## if name is None and requestData is not None:
895 name = requestData[0].url() 348 ## name = requestData[0].url()
896 349 ##
897 if self.ctrlPressed: 350 if self.__ctrlPressed:
898 # open in a new window 351 # open in a new window
899 self.mw.newTab(name) 352 self.__mw.newTab(name)
900 self.ctrlPressed = False 353 self.__ctrlPressed = False
901 return 354 return
902 355
903 if not name.scheme(): 356 if not name.scheme():
904 name.setUrl(Preferences.getHelp("DefaultScheme") + name.toString()) 357 name.setUrl(Preferences.getWebBrowser("DefaultScheme") +
905 358 name.toString())
359
360 # TODO: move some of this to web page
906 if len(name.scheme()) == 1 or \ 361 if len(name.scheme()) == 1 or \
907 name.scheme() == "file": 362 name.scheme() == "file":
908 # name is a local file 363 # name is a local file
909 if name.scheme() and len(name.scheme()) == 1: 364 if name.scheme() and len(name.scheme()) == 1:
910 # it is a local path on win os 365 # it is a local path on win os
942 self.tr( 397 self.tr(
943 """<p>Could not start an application""" 398 """<p>Could not start an application"""
944 """ for URL <b>{0}</b>.</p>""") 399 """ for URL <b>{0}</b>.</p>""")
945 .format(name.toString())) 400 .format(name.toString()))
946 return 401 return
947 elif name.scheme() == "javascript": 402 ## elif name.scheme() == "javascript":
948 scriptSource = QUrl.fromPercentEncoding(name.toString( 403 ## scriptSource = QUrl.fromPercentEncoding(name.toString(
949 QUrl.FormattingOptions(QUrl.TolerantMode | QUrl.RemoveScheme))) 404 ## QUrl.FormattingOptions(QUrl.TolerantMode | QUrl.RemoveScheme)))
950 self.page().mainFrame().evaluateJavaScript(scriptSource) 405 ## self.page().mainFrame().evaluateJavaScript(scriptSource)
951 return 406 ## return
952 else: 407 else:
953 if name.toString().endswith(".pdf") or \ 408 if name.toString().endswith(".pdf") or \
954 name.toString().endswith(".PDF") or \ 409 name.toString().endswith(".PDF") or \
955 name.toString().endswith(".chm") or \ 410 name.toString().endswith(".chm") or \
956 name.toString().endswith(".CHM"): 411 name.toString().endswith(".CHM"):
988 443
989 def backward(self): 444 def backward(self):
990 """ 445 """
991 Public slot to move backwards in history. 446 Public slot to move backwards in history.
992 """ 447 """
993 self.triggerPageAction(QWebPage.Back) 448 self.triggerPageAction(QWebEnginePage.Back)
994 self.__urlChanged(self.history().currentItem().url()) 449 self.__urlChanged(self.history().currentItem().url())
995 450
996 def forward(self): 451 def forward(self):
997 """ 452 """
998 Public slot to move forward in history. 453 Public slot to move forward in history.
999 """ 454 """
1000 self.triggerPageAction(QWebPage.Forward) 455 self.triggerPageAction(QWebEnginePage.Forward)
1001 self.__urlChanged(self.history().currentItem().url()) 456 self.__urlChanged(self.history().currentItem().url())
1002 457
1003 def home(self): 458 def home(self):
1004 """ 459 """
1005 Public slot to move to the first page loaded. 460 Public slot to move to the first page loaded.
1006 """ 461 """
1007 homeUrl = QUrl(Preferences.getHelp("HomePage")) 462 homeUrl = QUrl(Preferences.getWebBrowser("HomePage"))
1008 self.setSource(homeUrl) 463 self.setSource(homeUrl)
1009 self.__urlChanged(self.history().currentItem().url()) 464 self.__urlChanged(self.history().currentItem().url())
1010 465
1011 def reload(self): 466 def reload(self):
1012 """ 467 """
1013 Public slot to reload the current page. 468 Public slot to reload the current page.
1014 """ 469 """
1015 self.triggerPageAction(QWebPage.Reload) 470 self.triggerPageAction(QWebEnginePage.Reload)
1016 471
1017 def copy(self): 472 def copy(self):
1018 """ 473 """
1019 Public slot to copy the selected text. 474 Public slot to copy the selected text.
1020 """ 475 """
1021 self.triggerPageAction(QWebPage.Copy) 476 self.triggerPageAction(QWebEnginePage.Copy)
1022 477
1023 def isForwardAvailable(self): 478 def isForwardAvailable(self):
1024 """ 479 """
1025 Public method to determine, if a forward move in history is possible. 480 Public method to determine, if a forward move in history is possible.
1026 481
1065 @keyparam saveValue flag indicating to save the zoom value with the 520 @keyparam saveValue flag indicating to save the zoom value with the
1066 zoom manager 521 zoom manager
1067 @type bool 522 @type bool
1068 """ 523 """
1069 if value != self.zoomValue(): 524 if value != self.zoomValue():
1070 try: 525 self.setZoomFactor(value / 100.0)
1071 self.setZoomFactor(value / 100.0)
1072 except AttributeError:
1073 self.setTextSizeMultiplier(value / 100.0)
1074 self.__currentZoom = value 526 self.__currentZoom = value
1075 if saveValue: 527 # TODO: re-enable this when Zoom Manager is done
1076 Helpviewer.HelpWindow.HelpWindow.zoomManager().setZoomValue( 528 ## if saveValue:
1077 self.url(), value) 529 ## Helpviewer.HelpWindow.HelpWindow.zoomManager().setZoomValue(
530 ## self.url(), value)
1078 self.zoomValueChanged.emit(value) 531 self.zoomValueChanged.emit(value)
1079 532
1080 def zoomValue(self): 533 def zoomValue(self):
1081 """ 534 """
1082 Public method to get the current zoom value. 535 Public method to get the current zoom value.
1083 536
1084 @return zoom value (integer) 537 @return zoom value (integer)
1085 """ 538 """
1086 try: 539 val = self.zoomFactor() * 100
1087 val = self.zoomFactor() * 100
1088 except AttributeError:
1089 val = self.textSizeMultiplier() * 100
1090 return int(val) 540 return int(val)
1091 541
1092 def zoomIn(self): 542 def zoomIn(self):
1093 """ 543 """
1094 Public slot to zoom into the page. 544 Public slot to zoom into the page.
1109 559
1110 def zoomReset(self): 560 def zoomReset(self):
1111 """ 561 """
1112 Public method to reset the zoom factor. 562 Public method to reset the zoom factor.
1113 """ 563 """
1114 index = self.__levelForZoom(HelpBrowser.ZoomLevelDefault) 564 index = self.__levelForZoom(WebBrowserView.ZoomLevelDefault)
1115 self.__currentZoom = self.__zoomLevels[index] 565 self.__currentZoom = self.__zoomLevels[index]
1116 self.__applyZoom() 566 self.__applyZoom()
1117 567
1118 def hasSelection(self): 568 def hasSelection(self):
1119 """ 569 """
1121 571
1122 @return flag indicating text has been selected (boolean) 572 @return flag indicating text has been selected (boolean)
1123 """ 573 """
1124 return self.selectedText() != "" 574 return self.selectedText() != ""
1125 575
576 # FIXME: do this first
1126 def findNextPrev(self, txt, case, backwards, wrap, highlightAll): 577 def findNextPrev(self, txt, case, backwards, wrap, highlightAll):
1127 """ 578 """
1128 Public slot to find the next occurrence of a text. 579 Public slot to find the next occurrence of a text.
1129 580
1130 @param txt text to search for (string) 581 @param txt text to search for (string)
1302 pageMenu = None 753 pageMenu = None
1303 754
1304 if not menu.isEmpty(): 755 if not menu.isEmpty():
1305 menu.addSeparator() 756 menu.addSeparator()
1306 757
1307 self.mw.personalInformationManager().createSubMenu(menu, self, hit) 758 self.__mw.personalInformationManager().createSubMenu(menu, self, hit)
1308 759
1309 menu.addAction(self.mw.newTabAct) 760 menu.addAction(self.__mw.newTabAct)
1310 menu.addAction(self.mw.newAct) 761 menu.addAction(self.__mw.newAct)
1311 menu.addSeparator() 762 menu.addSeparator()
1312 menu.addAction(self.mw.saveAsAct) 763 menu.addAction(self.__mw.saveAsAct)
1313 menu.addSeparator() 764 menu.addSeparator()
1314 765
1315 if frameAtPos and self.page().mainFrame() != frameAtPos: 766 if frameAtPos and self.page().mainFrame() != frameAtPos:
1316 self.__clickedFrame = frameAtPos 767 self.__clickedFrame = frameAtPos
1317 fmenu = QMenu(self.tr("This Frame")) 768 fmenu = QMenu(self.tr("This Frame"))
1361 menu.addSeparator() 812 menu.addSeparator()
1362 self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"), 813 self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"),
1363 url=self.url()) 814 url=self.url())
1364 menu.addMenu(self.__userAgentMenu) 815 menu.addMenu(self.__userAgentMenu)
1365 menu.addSeparator() 816 menu.addSeparator()
1366 menu.addAction(self.mw.backAct) 817 menu.addAction(self.__mw.backAct)
1367 menu.addAction(self.mw.forwardAct) 818 menu.addAction(self.__mw.forwardAct)
1368 menu.addAction(self.mw.homeAct) 819 menu.addAction(self.__mw.homeAct)
1369 menu.addSeparator() 820 menu.addSeparator()
1370 menu.addAction(self.mw.zoomInAct) 821 menu.addAction(self.__mw.zoomInAct)
1371 menu.addAction(self.mw.zoomResetAct) 822 menu.addAction(self.__mw.zoomResetAct)
1372 menu.addAction(self.mw.zoomOutAct) 823 menu.addAction(self.__mw.zoomOutAct)
1373 menu.addSeparator() 824 menu.addSeparator()
1374 if self.selectedText(): 825 if self.selectedText():
1375 menu.addAction(self.mw.copyAct) 826 menu.addAction(self.__mw.copyAct)
1376 menu.addAction( 827 menu.addAction(
1377 UI.PixmapCache.getIcon("mailSend.png"), 828 UI.PixmapCache.getIcon("mailSend.png"),
1378 self.tr("Send Text"), 829 self.tr("Send Text"),
1379 self.__sendLink).setData(self.selectedText()) 830 self.__sendLink).setData(self.selectedText())
1380 menu.addAction(self.mw.findAct) 831 menu.addAction(self.__mw.findAct)
1381 menu.addSeparator() 832 menu.addSeparator()
1382 if self.selectedText(): 833 if self.selectedText():
1383 self.__searchMenu = menu.addMenu(self.tr("Search with...")) 834 self.__searchMenu = menu.addMenu(self.tr("Search with..."))
1384 835
1385 from .OpenSearch.OpenSearchEngineAction import \ 836 from .OpenSearch.OpenSearchEngineAction import \
1386 OpenSearchEngineAction 837 OpenSearchEngineAction
1387 engineNames = self.mw.openSearchManager().allEnginesNames() 838 engineNames = self.__mw.openSearchManager().allEnginesNames()
1388 for engineName in engineNames: 839 for engineName in engineNames:
1389 engine = self.mw.openSearchManager().engine(engineName) 840 engine = self.__mw.openSearchManager().engine(engineName)
1390 act = OpenSearchEngineAction(engine, self.__searchMenu) 841 act = OpenSearchEngineAction(engine, self.__searchMenu)
1391 act.setData(engineName) 842 act.setData(engineName)
1392 self.__searchMenu.addAction(act) 843 self.__searchMenu.addAction(act)
1393 self.__searchMenu.triggered.connect(self.__searchRequested) 844 self.__searchMenu.triggered.connect(self.__searchRequested)
1394 845
1459 act = self.sender() 910 act = self.sender()
1460 url = act.data() 911 url = act.data()
1461 if url.isEmpty(): 912 if url.isEmpty():
1462 return 913 return
1463 914
1464 self.ctrlPressed = True 915 self.__ctrlPressed = True
1465 self.setSource(url) 916 self.setSource(url)
1466 self.ctrlPressed = False 917 self.__ctrlPressed = False
1467 918
1468 def __bookmarkLink(self): 919 def __bookmarkLink(self):
1469 """ 920 """
1470 Private slot to bookmark a link via the context menu. 921 Private slot to bookmark a link via the context menu.
1471 """ 922 """
1538 """ 989 """
1539 Private slot to download a media and save it to disk. 990 Private slot to download a media and save it to disk.
1540 """ 991 """
1541 act = self.sender() 992 act = self.sender()
1542 url = act.data() 993 url = act.data()
1543 self.mw.downloadManager().download(url, True, mainWindow=self.mw) 994 self.__mw.downloadManager().download(url, True, mainWindow=self.__mw)
1544 995
1545 def __pauseMedia(self): 996 def __pauseMedia(self):
1546 """ 997 """
1547 Private slot to pause or play the selected media. 998 Private slot to pause or play the selected media.
1548 """ 999 """
1568 """ 1019 """
1569 Private slot to scan the selected URL with VirusTotal. 1020 Private slot to scan the selected URL with VirusTotal.
1570 """ 1021 """
1571 act = self.sender() 1022 act = self.sender()
1572 url = act.data() 1023 url = act.data()
1573 self.mw.requestVirusTotalScan(url) 1024 self.__mw.requestVirusTotalScan(url)
1574 1025
1575 def __searchRequested(self, act): 1026 def __searchRequested(self, act):
1576 """ 1027 """
1577 Private slot to search for some text with a selected search engine. 1028 Private slot to search for some text with a selected search engine.
1578 1029
1583 if not searchText: 1034 if not searchText:
1584 return 1035 return
1585 1036
1586 engineName = act.data() 1037 engineName = act.data()
1587 if engineName: 1038 if engineName:
1588 engine = self.mw.openSearchManager().engine(engineName) 1039 engine = self.__mw.openSearchManager().engine(engineName)
1589 self.search.emit(engine.searchUrl(searchText)) 1040 self.search.emit(engine.searchUrl(searchText))
1590 1041
1591 def __addSearchEngine(self): 1042 def __addSearchEngine(self):
1592 """ 1043 """
1593 Private slot to add a new search engine. 1044 Private slot to add a new search engine.
1706 engine.setName(engineName) 1157 engine.setName(engineName)
1707 engine.setDescription(engineName) 1158 engine.setDescription(engineName)
1708 engine.setSearchUrlTemplate(searchUrl.toString()) 1159 engine.setSearchUrlTemplate(searchUrl.toString())
1709 engine.setImage(self.icon().pixmap(16, 16).toImage()) 1160 engine.setImage(self.icon().pixmap(16, 16).toImage())
1710 1161
1711 self.mw.openSearchManager().addEngine(engine) 1162 self.__mw.openSearchManager().addEngine(engine)
1712 1163
1713 def __webInspector(self): 1164 def __webInspector(self):
1714 """ 1165 """
1715 Private slot to show the web inspector window. 1166 Private slot to show the web inspector window.
1716 """ 1167 """
1796 """ 1247 """
1797 Protected method called by a mouse press event. 1248 Protected method called by a mouse press event.
1798 1249
1799 @param evt reference to the mouse event (QMouseEvent) 1250 @param evt reference to the mouse event (QMouseEvent)
1800 """ 1251 """
1801 self.mw.setEventMouseButtons(evt.buttons()) 1252 self.__mw.setEventMouseButtons(evt.buttons())
1802 self.mw.setEventKeyboardModifiers(evt.modifiers()) 1253 self.__mw.setEventKeyboardModifiers(evt.modifiers())
1803 1254
1804 if evt.button() == Qt.XButton1: 1255 if evt.button() == Qt.XButton1:
1805 self.pageAction(QWebPage.Back).trigger() 1256 self.pageAction(QWebPage.Back).trigger()
1806 elif evt.button() == Qt.XButton2: 1257 elif evt.button() == Qt.XButton2:
1807 self.pageAction(QWebPage.Forward).trigger() 1258 self.pageAction(QWebPage.Forward).trigger()
1815 @param evt reference to the mouse event (QMouseEvent) 1266 @param evt reference to the mouse event (QMouseEvent)
1816 """ 1267 """
1817 accepted = evt.isAccepted() 1268 accepted = evt.isAccepted()
1818 self.__page.event(evt) 1269 self.__page.event(evt)
1819 if not evt.isAccepted() and \ 1270 if not evt.isAccepted() and \
1820 self.mw.eventMouseButtons() & Qt.MidButton: 1271 self.__mw.eventMouseButtons() & Qt.MidButton:
1821 url = QUrl(QApplication.clipboard().text(QClipboard.Selection)) 1272 url = QUrl(QApplication.clipboard().text(QClipboard.Selection))
1822 if not url.isEmpty() and \ 1273 if not url.isEmpty() and \
1823 url.isValid() and \ 1274 url.isValid() and \
1824 url.scheme() != "": 1275 url.scheme() != "":
1825 self.mw.setEventMouseButtons(Qt.NoButton) 1276 self.__mw.setEventMouseButtons(Qt.NoButton)
1826 self.mw.setEventKeyboardModifiers(Qt.NoModifier) 1277 self.__mw.setEventKeyboardModifiers(Qt.NoModifier)
1827 self.setSource(url) 1278 self.setSource(url)
1828 evt.setAccepted(accepted) 1279 evt.setAccepted(accepted)
1829 1280
1830 def wheelEvent(self, evt): 1281 def wheelEvent(self, evt):
1831 """ 1282 """
1859 """ 1310 """
1860 Protected method called by a key press. 1311 Protected method called by a key press.
1861 1312
1862 @param evt reference to the key event (QKeyEvent) 1313 @param evt reference to the key event (QKeyEvent)
1863 """ 1314 """
1864 if self.mw.personalInformationManager().viewKeyPressEvent(self, evt): 1315 if self.__mw.personalInformationManager().viewKeyPressEvent(self, evt):
1865 return 1316 return
1866 1317
1867 if self.__enableAccessKeys: 1318 if self.__enableAccessKeys:
1868 self.__accessKeysPressed = ( 1319 self.__accessKeysPressed = (
1869 evt.modifiers() == Qt.ControlModifier and 1320 evt.modifiers() == Qt.ControlModifier and
1875 return 1326 return
1876 self.__hideAccessKeys() 1327 self.__hideAccessKeys()
1877 else: 1328 else:
1878 QTimer.singleShot(300, self.__accessKeyShortcut) 1329 QTimer.singleShot(300, self.__accessKeyShortcut)
1879 1330
1880 self.ctrlPressed = (evt.key() == Qt.Key_Control) 1331 self.__ctrlPressed = (evt.key() == Qt.Key_Control)
1881 super(HelpBrowser, self).keyPressEvent(evt) 1332 super(HelpBrowser, self).keyPressEvent(evt)
1882 1333
1883 def keyReleaseEvent(self, evt): 1334 def keyReleaseEvent(self, evt):
1884 """ 1335 """
1885 Protected method called by a key release. 1336 Protected method called by a key release.
1887 @param evt reference to the key event (QKeyEvent) 1338 @param evt reference to the key event (QKeyEvent)
1888 """ 1339 """
1889 if self.__enableAccessKeys: 1340 if self.__enableAccessKeys:
1890 self.__accessKeysPressed = evt.key() == Qt.Key_Control 1341 self.__accessKeysPressed = evt.key() == Qt.Key_Control
1891 1342
1892 self.ctrlPressed = False 1343 self.__ctrlPressed = False
1893 super(HelpBrowser, self).keyReleaseEvent(evt) 1344 super(HelpBrowser, self).keyReleaseEvent(evt)
1894 1345
1895 def focusOutEvent(self, evt): 1346 def focusOutEvent(self, evt):
1896 """ 1347 """
1897 Protected method called by a focus out event. 1348 Protected method called by a focus out event.
1953 self.sourceChanged.emit(url) 1404 self.sourceChanged.emit(url)
1954 1405
1955 self.forwardAvailable.emit(self.isForwardAvailable()) 1406 self.forwardAvailable.emit(self.isForwardAvailable())
1956 self.backwardAvailable.emit(self.isBackwardAvailable()) 1407 self.backwardAvailable.emit(self.isBackwardAvailable())
1957 1408
1958 def __statusBarMessage(self, text): 1409 ## def __statusBarMessage(self, text):
1959 """ 1410 ## """
1960 Private slot to handle the statusBarMessage signal. 1411 ## Private slot to handle the statusBarMessage signal.
1961 1412 ##
1962 @param text text to be shown in the status bar (string) 1413 ## @param text text to be shown in the status bar (string)
1963 """ 1414 ## """
1964 self.mw.statusBar().showMessage(text) 1415 ## self.__mw.statusBar().showMessage(text)
1965 1416 ##
1966 def __linkHovered(self, link, title, textContent): 1417 def __linkHovered(self, link, title, textContent):
1967 """ 1418 """
1968 Private slot to handle the linkHovered signal. 1419 Private slot to handle the linkHovered signal.
1969 1420
1970 @param link the URL of the link (string) 1421 @param link the URL of the link (string)
2009 zoomValue = Helpviewer.HelpWindow.HelpWindow.zoomManager()\ 1460 zoomValue = Helpviewer.HelpWindow.HelpWindow.zoomManager()\
2010 .zoomValue(self.url()) 1461 .zoomValue(self.url())
2011 self.setZoomValue(zoomValue) 1462 self.setZoomValue(zoomValue)
2012 1463
2013 if ok: 1464 if ok:
2014 self.mw.adBlockManager().page().hideBlockedPageEntries(self.page()) 1465 self.__mw.adBlockManager().page().hideBlockedPageEntries(self.page())
2015 self.mw.passwordManager().fill(self.page()) 1466 self.__mw.passwordManager().fill(self.page())
2016 1467
2017 def isLoading(self): 1468 def isLoading(self):
2018 """ 1469 """
2019 Public method to get the loading state. 1470 Public method to get the loading state.
2020 1471
2036 """ 1487 """
2037 url = self.url() 1488 url = self.url()
2038 if url.isEmpty(): 1489 if url.isEmpty():
2039 return 1490 return
2040 1491
2041 self.mw.downloadManager().download(url, True, mainWindow=self.mw) 1492 self.__mw.downloadManager().download(url, True, mainWindow=self.__mw)
2042 1493
2043 def __unsupportedContent(self, reply, requestFilename=None, 1494 ## def __unsupportedContent(self, reply, requestFilename=None,
2044 download=False): 1495 ## download=False):
2045 """ 1496 ## """
2046 Private slot to handle the unsupportedContent signal. 1497 ## Private slot to handle the unsupportedContent signal.
2047 1498 ##
2048 @param reply reference to the reply object (QNetworkReply) 1499 ## @param reply reference to the reply object (QNetworkReply)
2049 @keyparam requestFilename indicating to ask for a filename 1500 ## @keyparam requestFilename indicating to ask for a filename
2050 (boolean or None). If it is None, the behavior is determined 1501 ## (boolean or None). If it is None, the behavior is determined
2051 by a configuration option. 1502 ## by a configuration option.
2052 @keyparam download flag indicating a download operation (boolean) 1503 ## @keyparam download flag indicating a download operation (boolean)
2053 """ 1504 ## """
2054 if reply is None: 1505 ## if reply is None:
2055 return 1506 ## return
2056 1507 ##
2057 replyUrl = reply.url() 1508 ## replyUrl = reply.url()
2058 1509 ##
2059 if replyUrl.scheme() == "abp": 1510 ## if replyUrl.scheme() == "abp":
2060 return 1511 ## return
2061 1512 ##
2062 if reply.error() == QNetworkReply.NoError: 1513 ## if reply.error() == QNetworkReply.NoError:
2063 if reply.header(QNetworkRequest.ContentTypeHeader): 1514 ## if reply.header(QNetworkRequest.ContentTypeHeader):
2064 self.mw.downloadManager().handleUnsupportedContent( 1515 ## self.__mw.downloadManager().handleUnsupportedContent(
2065 reply, webPage=self.page(), mainWindow=self.mw) 1516 ## reply, webPage=self.page(), mainWindow=self.__mw)
2066 return 1517 ## return
2067 1518 ##
2068 replyUrl = reply.url() 1519 ## replyUrl = reply.url()
2069 if replyUrl.isEmpty(): 1520 ## if replyUrl.isEmpty():
2070 return 1521 ## return
2071 1522 ##
2072 notFoundFrame = self.page().mainFrame() 1523 ## notFoundFrame = self.page().mainFrame()
2073 if notFoundFrame is None: 1524 ## if notFoundFrame is None:
2074 return 1525 ## return
2075 1526 ##
2076 if reply.header(QNetworkRequest.ContentTypeHeader): 1527 ## if reply.header(QNetworkRequest.ContentTypeHeader):
2077 data = reply.readAll() 1528 ## data = reply.readAll()
2078 if contentSniff(data): 1529 ## if contentSniff(data):
2079 notFoundFrame.setHtml(str(data, encoding="utf-8"), replyUrl) 1530 ## notFoundFrame.setHtml(str(data, encoding="utf-8"), replyUrl)
2080 return 1531 ## return
2081 1532 ##
2082 urlString = bytes(replyUrl.toEncoded()).decode() 1533 ## urlString = bytes(replyUrl.toEncoded()).decode()
2083 title = self.tr("Error loading page: {0}").format(urlString) 1534 ## title = self.tr("Error loading page: {0}").format(urlString)
2084 htmlFile = QFile(":/html/notFoundPage.html") 1535 ## htmlFile = QFile(":/html/notFoundPage.html")
2085 htmlFile.open(QFile.ReadOnly) 1536 ## htmlFile.open(QFile.ReadOnly)
2086 html = htmlFile.readAll() 1537 ## html = htmlFile.readAll()
2087 pixmap = qApp.style()\ 1538 ## pixmap = qApp.style()\
2088 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48) 1539 ## .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48)
2089 imageBuffer = QBuffer() 1540 ## imageBuffer = QBuffer()
2090 imageBuffer.open(QIODevice.ReadWrite) 1541 ## imageBuffer.open(QIODevice.ReadWrite)
2091 if pixmap.save(imageBuffer, "PNG"): 1542 ## if pixmap.save(imageBuffer, "PNG"):
2092 html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64()) 1543 ## html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64())
2093 pixmap = qApp.style()\ 1544 ## pixmap = qApp.style()\
2094 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16) 1545 ## .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16)
2095 imageBuffer = QBuffer() 1546 ## imageBuffer = QBuffer()
2096 imageBuffer.open(QIODevice.ReadWrite) 1547 ## imageBuffer.open(QIODevice.ReadWrite)
2097 if pixmap.save(imageBuffer, "PNG"): 1548 ## if pixmap.save(imageBuffer, "PNG"):
2098 html = html.replace("@FAVICON@", imageBuffer.buffer().toBase64()) 1549 ## html = html.replace("@FAVICON@", imageBuffer.buffer().toBase64())
2099 html = html.replace("@TITLE@", title.encode("utf8")) 1550 ## html = html.replace("@TITLE@", title.encode("utf8"))
2100 html = html.replace("@H1@", reply.errorString().encode("utf8")) 1551 ## html = html.replace("@H1@", reply.errorString().encode("utf8"))
2101 html = html.replace( 1552 ## html = html.replace(
2102 "@H2@", self.tr("When connecting to: {0}.") 1553 ## "@H2@", self.tr("When connecting to: {0}.")
2103 .format(urlString).encode("utf8")) 1554 ## .format(urlString).encode("utf8"))
2104 html = html.replace( 1555 ## html = html.replace(
2105 "@LI-1@", 1556 ## "@LI-1@",
2106 self.tr("Check the address for errors such as " 1557 ## self.tr("Check the address for errors such as "
2107 "<b>ww</b>.example.org instead of " 1558 ## "<b>ww</b>.example.org instead of "
2108 "<b>www</b>.example.org").encode("utf8")) 1559 ## "<b>www</b>.example.org").encode("utf8"))
2109 html = html.replace( 1560 ## html = html.replace(
2110 "@LI-2@", 1561 ## "@LI-2@",
2111 self.tr("If the address is correct, try checking the network " 1562 ## self.tr("If the address is correct, try checking the network "
2112 "connection.").encode("utf8")) 1563 ## "connection.").encode("utf8"))
2113 html = html.replace( 1564 ## html = html.replace(
2114 "@LI-3@", 1565 ## "@LI-3@",
2115 self.tr( 1566 ## self.tr(
2116 "If your computer or network is protected by a firewall " 1567 ## "If your computer or network is protected by a firewall "
2117 "or proxy, make sure that the browser is permitted to " 1568 ## "or proxy, make sure that the browser is permitted to "
2118 "access the network.").encode("utf8")) 1569 ## "access the network.").encode("utf8"))
2119 html = html.replace( 1570 ## html = html.replace(
2120 "@LI-4@", 1571 ## "@LI-4@",
2121 self.tr("If your cache policy is set to offline browsing," 1572 ## self.tr("If your cache policy is set to offline browsing,"
2122 "only pages in the local cache are available.") 1573 ## "only pages in the local cache are available.")
2123 .encode("utf8")) 1574 ## .encode("utf8"))
2124 html = html.replace( 1575 ## html = html.replace(
2125 "@BUTTON@", self.tr("Try Again").encode("utf8")) 1576 ## "@BUTTON@", self.tr("Try Again").encode("utf8"))
2126 notFoundFrame.setHtml(bytes(html).decode("utf8"), replyUrl) 1577 ## notFoundFrame.setHtml(bytes(html).decode("utf8"), replyUrl)
2127 self.mw.historyManager().removeHistoryEntry(replyUrl, self.title()) 1578 ## self.__mw.historyManager().removeHistoryEntry(replyUrl, self.title())
2128 self.loadFinished.emit(False) 1579 ## self.loadFinished.emit(False)
2129 1580 ##
2130 def __featurePermissionRequested(self, frame, feature):
2131 """
2132 Private slot handling a feature permission request.
2133
2134 @param frame frame sending the request
2135 @type QWebFrame
2136 @param feature requested feature
2137 @type QWebPage.Feature
2138 """
2139 manager = Helpviewer.HelpWindow.HelpWindow.featurePermissionManager()
2140 manager.requestFeaturePermission(self.page(), frame, feature)
2141 1581
2142 def __downloadRequested(self, request): 1582 def __downloadRequested(self, request):
2143 """ 1583 """
2144 Private slot to handle a download request. 1584 Private slot to handle a download request.
2145 1585
2146 @param request reference to the request object (QNetworkRequest) 1586 @param request reference to the request object (QNetworkRequest)
2147 """ 1587 """
2148 self.mw.downloadManager().download(request, mainWindow=self.mw) 1588 self.__mw.downloadManager().download(request, mainWindow=self.__mw)
2149 1589
2150 def __databaseQuotaExceeded(self, frame, databaseName): 1590 def __databaseQuotaExceeded(self, frame, databaseName):
2151 """ 1591 """
2152 Private slot to handle the case, where the database quota is exceeded. 1592 Private slot to handle the case, where the database quota is exceeded.
2153 1593
2376 Public method called, when a new window should be created. 1816 Public method called, when a new window should be created.
2377 1817
2378 @param windowType type of the requested window (QWebPage.WebWindowType) 1818 @param windowType type of the requested window (QWebPage.WebWindowType)
2379 @return reference to the created browser window (HelpBrowser) 1819 @return reference to the created browser window (HelpBrowser)
2380 """ 1820 """
2381 self.mw.newTab(addNextTo=self) 1821 self.__mw.newTab(addNextTo=self)
2382 return self.mw.currentBrowser() 1822 return self.__mw.currentBrowser()
2383 1823
2384 def preferencesChanged(self): 1824 def preferencesChanged(self):
2385 """ 1825 """
2386 Public method to indicate a change of the settings. 1826 Public method to indicate a change of the settings.
2387 """ 1827 """

eric ide

mercurial