7 """ |
7 """ |
8 Module implementing the helpbrowser using QWebView. |
8 Module implementing the helpbrowser using QWebView. |
9 """ |
9 """ |
10 |
10 |
11 from PyQt4.QtCore import pyqtSlot, pyqtSignal, QObject, QT_TRANSLATE_NOOP, QUrl, \ |
11 from PyQt4.QtCore import pyqtSlot, pyqtSignal, QObject, QT_TRANSLATE_NOOP, QUrl, \ |
12 QBuffer, QIODevice, QFileInfo, Qt, QTimer, QEvent, QRect, QFile |
12 QBuffer, QIODevice, QFileInfo, Qt, QTimer, QEvent, QRect, QFile, QPoint |
13 from PyQt4.QtGui import qApp, QDesktopServices, QStyle, QMenu, QApplication, \ |
13 from PyQt4.QtGui import qApp, QDesktopServices, QStyle, QMenu, QApplication, \ |
14 QInputDialog, QLineEdit, QClipboard, QMouseEvent, QLabel, QToolTip, QColor, \ |
14 QInputDialog, QLineEdit, QClipboard, QMouseEvent, QLabel, QToolTip, QColor, \ |
15 QPalette, QFrame, QPrinter, QPrintDialog, QDialog |
15 QPalette, QFrame, QPrinter, QPrintDialog, QDialog |
16 from PyQt4 import QtWebKit |
16 from PyQt4 import QtWebKit |
17 from PyQt4.QtWebKit import QWebView, QWebPage, QWebSettings |
17 from PyQt4.QtWebKit import QWebView, QWebPage, QWebSettings |
256 @param extension extension to be executed (QWebPage.Extension) |
256 @param extension extension to be executed (QWebPage.Extension) |
257 @param option provides input to the extension (QWebPage.ExtensionOption) |
257 @param option provides input to the extension (QWebPage.ExtensionOption) |
258 @param output stores the output results (QWebPage.ExtensionReturn) |
258 @param output stores the output results (QWebPage.ExtensionReturn) |
259 @return flag indicating a successful call of the extension (boolean) |
259 @return flag indicating a successful call of the extension (boolean) |
260 """ |
260 """ |
261 try: |
261 if extension == QWebPage.ChooseMultipleFilesExtension: |
262 if extension == QWebPage.ErrorPageExtension: |
262 info = sip.cast(option, QWebPage.ChooseMultipleFilesExtensionOption) |
263 info = sip.cast(option, QWebPage.ErrorPageExtensionOption) |
263 files = sip.cast(output, QWebPage.ChooseMultipleFilesExtensionReturn) |
264 if info.error == 102: |
264 if info is None or files is None: |
265 # this is something of a hack; hopefully it will work in the future |
265 return super().extension(extension, option, output) |
|
266 |
|
267 suggestedFileName = "" |
|
268 if info.suggestedFileNames: |
|
269 suggestedFileName = info.suggestedFileNames[0] |
|
270 |
|
271 files.fileNames = E5FileDialog.getOpenFileNames( |
|
272 None, |
|
273 self.trUtf8("Select files to upload..."), |
|
274 suggestedFileName) |
|
275 return True |
|
276 |
|
277 ## if (extension == ChooseMultipleFilesExtension) { |
|
278 ## const QWebPage::ChooseMultipleFilesExtensionOption* exOption = static_cast<const QWebPage::ChooseMultipleFilesExtensionOption*>(option); |
|
279 ## QWebPage::ChooseMultipleFilesExtensionReturn* exReturn = static_cast<QWebPage::ChooseMultipleFilesExtensionReturn*>(output); |
|
280 ## |
|
281 ## if (!exOption || !exReturn) { |
|
282 ## return QWebPage::extension(extension, option, output); |
|
283 ## } |
|
284 ## |
|
285 ## QString suggestedFileName; |
|
286 ## if (!exOption->suggestedFileNames.isEmpty()) { |
|
287 ## suggestedFileName = exOption->suggestedFileNames.at(0); |
|
288 ## } |
|
289 ## |
|
290 ## exReturn->fileNames = QFileDialog::getOpenFileNames(0, tr("Select files to upload..."), suggestedFileName); |
|
291 ## return true; |
|
292 ## } |
|
293 if extension == QWebPage.ErrorPageExtension: |
|
294 info = sip.cast(option, QWebPage.ErrorPageExtensionOption) |
|
295 if info.error == 102: |
|
296 # this is something of a hack; hopefully it will work in the future |
|
297 return False |
|
298 |
|
299 errorPage = sip.cast(output, QWebPage.ErrorPageExtensionReturn) |
|
300 urlString = bytes(info.url.toEncoded()).decode() |
|
301 errorPage.baseUrl = info.url |
|
302 if info.domain == QWebPage.QtNetwork and \ |
|
303 info.error == QNetworkReply.ContentAccessDenied and \ |
|
304 info.errorString.startswith("AdBlockRule:"): |
|
305 if info.frame != info.frame.page().mainFrame(): |
|
306 # content in <iframe> |
|
307 docElement = info.frame.page().mainFrame().documentElement() |
|
308 for element in docElement.findAll("iframe"): |
|
309 src = element.attribute("src") |
|
310 if src in info.url.toString(): |
|
311 element.setAttribute("style", "display:none;") |
266 return False |
312 return False |
267 |
313 else: |
268 errorPage = sip.cast(output, QWebPage.ErrorPageExtensionReturn) |
314 # the whole page is blocked |
269 urlString = bytes(info.url.toEncoded()).decode() |
315 rule = info.errorString.replace("AdBlockRule:", "") |
270 errorPage.baseUrl = info.url |
316 title = self.trUtf8("Content blocked by AdBlock Plus") |
271 if info.domain == QWebPage.QtNetwork and \ |
317 message = self.trUtf8("Blocked by rule: <i>{0}</i>").format(rule) |
272 info.error == QNetworkReply.ContentAccessDenied and \ |
318 |
273 info.errorString.startswith("AdBlockRule:"): |
319 htmlFile = QFile(":/html/adblockPage.html") |
274 if info.frame != info.frame.page().mainFrame(): |
320 htmlFile.open(QFile.ReadOnly) |
275 # content in <iframe> |
321 html = htmlFile.readAll() |
276 docElement = info.frame.page().mainFrame().documentElement() |
322 html = html.replace("@FAVICON@", "qrc:icons/adBlockPlus16.png") |
277 for element in docElement.findAll("iframe"): |
323 html = html.replace("@IMAGE@", "qrc:icons/adBlockPlus64.png") |
278 src = element.attribute("src") |
324 html = html.replace("@TITLE@", title.encode("utf8")) |
279 if src in info.url.toString(): |
325 html = html.replace("@MESSAGE@", message.encode("utf8")) |
280 element.setAttribute("style", "display:none;") |
326 errorPage.content = html |
281 return False |
327 return True |
282 else: |
328 |
283 # the whole page is blocked |
329 title = self.trUtf8("Error loading page: {0}").format(urlString) |
284 rule = info.errorString.replace("AdBlockRule:", "") |
330 htmlFile = QFile(":/html/notFoundPage.html") |
285 title = self.trUtf8("Content blocked by AdBlock Plus") |
331 htmlFile.open(QFile.ReadOnly) |
286 message = self.trUtf8("Blocked by rule: <i>{0}</i>").format(rule) |
332 html = htmlFile.readAll() |
287 |
333 pixmap = qApp.style()\ |
288 htmlFile = QFile(":/html/adblockPage.html") |
334 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48) |
289 htmlFile.open(QFile.ReadOnly) |
335 imageBuffer = QBuffer() |
290 html = htmlFile.readAll() |
336 imageBuffer.open(QIODevice.ReadWrite) |
291 html = html.replace("@FAVICON@", "qrc:icons/adBlockPlus16.png") |
337 if pixmap.save(imageBuffer, "PNG"): |
292 html = html.replace("@IMAGE@", "qrc:icons/adBlockPlus64.png") |
338 html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64()) |
293 html = html.replace("@TITLE@", title.encode("utf8")) |
339 pixmap = qApp.style()\ |
294 html = html.replace("@MESSAGE@", message.encode("utf8")) |
340 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16) |
295 errorPage.content = html |
341 imageBuffer = QBuffer() |
296 return True |
342 imageBuffer.open(QIODevice.ReadWrite) |
297 |
343 if pixmap.save(imageBuffer, "PNG"): |
298 title = self.trUtf8("Error loading page: {0}").format(urlString) |
344 html = html.replace("@FAVICON@", imageBuffer.buffer().toBase64()) |
299 htmlFile = QFile(":/html/notFoundPage.html") |
345 html = html.replace("@TITLE@", title.encode("utf8")) |
300 htmlFile.open(QFile.ReadOnly) |
346 html = html.replace("@H1@", info.errorString.encode("utf8")) |
301 html = htmlFile.readAll() |
347 html = html.replace("@H2@", self.trUtf8("When connecting to: {0}.")\ |
302 pixmap = qApp.style()\ |
348 .format(urlString).encode("utf8")) |
303 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48) |
349 html = html.replace("@LI-1@", |
304 imageBuffer = QBuffer() |
350 self.trUtf8("Check the address for errors such as " |
305 imageBuffer.open(QIODevice.ReadWrite) |
351 "<b>ww</b>.example.org instead of " |
306 if pixmap.save(imageBuffer, "PNG"): |
352 "<b>www</b>.example.org").encode("utf8")) |
307 html = html.replace("@IMAGE@", imageBuffer.buffer().toBase64()) |
353 html = html.replace("@LI-2@", |
308 pixmap = qApp.style()\ |
354 self.trUtf8("If the address is correct, try checking the network " |
309 .standardIcon(QStyle.SP_MessageBoxWarning).pixmap(16, 16) |
355 "connection.").encode("utf8")) |
310 imageBuffer = QBuffer() |
356 html = html.replace("@LI-3@", |
311 imageBuffer.open(QIODevice.ReadWrite) |
357 self.trUtf8("If your computer or network is protected by a firewall " |
312 if pixmap.save(imageBuffer, "PNG"): |
358 "or proxy, make sure that the browser is permitted to " |
313 html = html.replace("@FAVICON@", imageBuffer.buffer().toBase64()) |
359 "access the network.").encode("utf8")) |
314 html = html.replace("@TITLE@", title.encode("utf8")) |
360 html = html.replace("@LI-4@", |
315 html = html.replace("@H1@", info.errorString.encode("utf8")) |
361 self.trUtf8("If your cache policy is set to offline browsing," |
316 html = html.replace("@H2@", self.trUtf8("When connecting to: {0}.")\ |
362 "only pages in the local cache are available.")\ |
317 .format(urlString).encode("utf8")) |
363 .encode("utf8")) |
318 html = html.replace("@LI-1@", |
364 html = html.replace("@BUTTON@", self.trUtf8("Try Again").encode("utf8")) |
319 self.trUtf8("Check the address for errors such as " |
365 errorPage.content = html |
320 "<b>ww</b>.example.org instead of " |
366 return True |
321 "<b>www</b>.example.org").encode("utf8")) |
|
322 html = html.replace("@LI-2@", |
|
323 self.trUtf8("If the address is correct, try checking the network " |
|
324 "connection.").encode("utf8")) |
|
325 html = html.replace("@LI-3@", |
|
326 self.trUtf8("If your computer or network is protected by a firewall " |
|
327 "or proxy, make sure that the browser is permitted to " |
|
328 "access the network.").encode("utf8")) |
|
329 html = html.replace("@LI-4@", |
|
330 self.trUtf8("If your cache policy is set to offline browsing," |
|
331 "only pages in the local cache are available.")\ |
|
332 .encode("utf8")) |
|
333 html = html.replace("@BUTTON@", self.trUtf8("Try Again").encode("utf8")) |
|
334 errorPage.content = html |
|
335 return True |
|
336 except AttributeError: |
|
337 pass |
|
338 |
367 |
339 return QWebPage.extension(self, extension, option, output) |
368 return QWebPage.extension(self, extension, option, output) |
340 |
369 |
341 def userAgent(self, resolveEmpty=False): |
370 def userAgent(self, resolveEmpty=False): |
342 """ |
371 """ |
951 menu.addAction(UI.PixmapCache.getIcon("virustotal.png"), |
1006 menu.addAction(UI.PixmapCache.getIcon("virustotal.png"), |
952 self.trUtf8("Scan Image with VirusTotal"), self.__virusTotal)\ |
1007 self.trUtf8("Scan Image with VirusTotal"), self.__virusTotal)\ |
953 .setData(hit.imageUrl()) |
1008 .setData(hit.imageUrl()) |
954 |
1009 |
955 element = hit.element() |
1010 element = hit.element() |
956 if not element.isNull() and \ |
1011 if not element.isNull(): |
957 element.tagName().lower() in ["input", "textarea", "video", "audio"]: |
1012 if self.__isMediaElement(element): |
958 if menu.isEmpty(): |
1013 if not menu.isEmpty(): |
959 self.page().createStandardContextMenu().exec_(evt.globalPos()) |
1014 menu.addSeparator() |
960 return |
1015 |
|
1016 self.__clickedMediaElement = element |
|
1017 |
|
1018 paused = element.evaluateJavaScript("this.paused") |
|
1019 muted = element.evaluateJavaScript("this.muted") |
|
1020 videoUrl = QUrl(element.evaluateJavaScript("this.currentSrc")) |
|
1021 |
|
1022 if paused: |
|
1023 menu.addAction(UI.PixmapCache.getIcon("mediaPlaybackStart.png"), |
|
1024 self.trUtf8("Play"), self.__pauseMedia) |
|
1025 else: |
|
1026 menu.addAction(UI.PixmapCache.getIcon("mediaPlaybackPause.png"), |
|
1027 self.trUtf8("Pause"), self.__pauseMedia) |
|
1028 if muted: |
|
1029 menu.addAction(UI.PixmapCache.getIcon("audioVolumeHigh.png"), |
|
1030 self.trUtf8("Unmute"), self.__muteMedia) |
|
1031 else: |
|
1032 menu.addAction(UI.PixmapCache.getIcon("audioVolumeMuted.png"), |
|
1033 self.trUtf8("Mute"), self.__muteMedia) |
|
1034 menu.addSeparator() |
|
1035 menu.addAction(UI.PixmapCache.getIcon("editCopy.png"), |
|
1036 self.trUtf8("Copy Media Address to Clipboard"), |
|
1037 self.__copyLocation).setData(videoUrl.toString()) |
|
1038 menu.addAction(UI.PixmapCache.getIcon("mailSend.png"), |
|
1039 self.trUtf8("Send Media Address"), self.__sendLink)\ |
|
1040 .setData(videoUrl) |
|
1041 menu.addAction(UI.PixmapCache.getIcon("download.png"), |
|
1042 self.trUtf8("Save Media"), self.__downloadMedia)\ |
|
1043 .setData(videoUrl) |
|
1044 |
|
1045 if element.tagName().lower() in ["input", "textarea"]: |
|
1046 if menu.isEmpty(): |
|
1047 self.page().createStandardContextMenu().exec_(evt.globalPos()) |
|
1048 return |
961 |
1049 |
962 if not menu.isEmpty(): |
1050 if not menu.isEmpty(): |
963 menu.addSeparator() |
1051 menu.addSeparator() |
964 menu.addAction(self.mw.newTabAct) |
1052 menu.addAction(self.mw.newTabAct) |
965 menu.addAction(self.mw.newAct) |
1053 menu.addAction(self.mw.newAct) |