Sat, 18 Feb 2017 19:59:14 +0100
Started upgrading the new web browser to the Qt 5.8 offerings.
--- a/Preferences/ConfigurationPages/WebBrowserPage.py Sat Feb 18 12:23:35 2017 +0100 +++ b/Preferences/ConfigurationPages/WebBrowserPage.py Sat Feb 18 19:59:14 2017 +0100 @@ -149,8 +149,28 @@ Preferences.getWebBrowser("SpatialNavigationEnabled")) self.linksInFocusChainCheckBox.setChecked( Preferences.getWebBrowser("LinksIncludedInFocusChain")) + try: + # Qt 5.8 + self.focusOnNavigationCheckBox.setChecked( + Preferences.getWebBrowser("FocusOnNavigationEnabled")) + except KeyError: + self.focusOnNavigationCheckBox.setEnabled(False) + self.xssAuditingCheckBox.setChecked( Preferences.getWebBrowser("XSSAuditingEnabled")) + try: + # Qt 5.8 + self.insecureContentsCheckBox.setChecked( + Preferences.getWebBrowser("AllowRunningInsecureContent")) + except KeyError: + self.insecureContentsCheckBox.setEnabled(False) + + try: + # Qt 5.8 + self.printBackgroundCheckBox.setChecked( + Preferences.getWebBrowser("PrintElementBackgrounds")) + except KeyError: + self.printBackgroundCheckBox.setEnabled(False) self.autoScrollGroupBox.setChecked( Preferences.getWebBrowser("AutoScrollEnabled")) @@ -265,9 +285,23 @@ Preferences.setWebBrowser( "LinksIncludedInFocusChain", self.linksInFocusChainCheckBox.isChecked()) + if self.focusOnNavigationCheckBox.isEnabled(): + Preferences.setWebBrowser( + "FocusOnNavigationEnabled", + self.focusOnNavigationCheckBox.isChecked()) + Preferences.setWebBrowser( "XSSAuditingEnabled", self.xssAuditingCheckBox.isChecked()) + if self.insecureContentsCheckBox.isEnabled(): + Preferences.setWebBrowser( + "AllowRunningInsecureContent", + self.insecureContentsCheckBox.isChecked()) + + if self.printBackgroundCheckBox.isEnabled(): + Preferences.setWebBrowser( + "PrintElementBackgrounds", + self.printBackgroundCheckBox.isChecked()) Preferences.setWebBrowser( "AutoScrollEnabled",
--- a/Preferences/ConfigurationPages/WebBrowserPage.ui Sat Feb 18 12:23:35 2017 +0100 +++ b/Preferences/ConfigurationPages/WebBrowserPage.ui Sat Feb 18 19:59:14 2017 +0100 @@ -7,10 +7,10 @@ <x>0</x> <y>0</y> <width>616</width> - <height>1533</height> + <height>1610</height> </rect> </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QLabel" name="headerLabel"> <property name="text"> @@ -360,7 +360,7 @@ <property name="title"> <string>Security</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QHBoxLayout" name="horizontalLayout_7"> <item> <widget class="QCheckBox" name="xssAuditingCheckBox"> <property name="toolTip"> @@ -375,6 +375,16 @@ </property> </widget> </item> + <item> + <widget class="QCheckBox" name="insecureContentsCheckBox"> + <property name="toolTip"> + <string>Select to allow HTTPS pages to run JavaScript, CSS, plugins or web-sockets from HTTP URLs</string> + </property> + <property name="text"> + <string>Allow to run insecure contents</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -577,7 +587,7 @@ <property name="title"> <string>Navigation</string> </property> - <layout class="QGridLayout" name="gridLayout_6"> + <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <widget class="QCheckBox" name="spatialCheckBox"> <property name="toolTip"> @@ -606,6 +616,35 @@ </property> </widget> </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="focusOnNavigationCheckBox"> + <property name="toolTip"> + <string>Select to give the focus to the view whenever a navigation event occurs</string> + </property> + <property name="text"> + <string>Enable Focus on Navigation</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_7"> + <property name="title"> + <string>Printing</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QCheckBox" name="printBackgroundCheckBox"> + <property name="toolTip"> + <string>Select to print the background of page elements as well</string> + </property> + <property name="text"> + <string>Print Element Backgrounds</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -771,12 +810,13 @@ <tabstop>errorPageCheckBox</tabstop> <tabstop>scrollingCheckBox</tabstop> <tabstop>fullscreenCheckBox</tabstop> + <tabstop>screenCaptureCheckBox</tabstop> + <tabstop>webGLCheckBox</tabstop> <tabstop>startupCombo</tabstop> <tabstop>homePageEdit</tabstop> <tabstop>setCurrentPageButton</tabstop> <tabstop>defaultHomeButton</tabstop> <tabstop>defaultSchemeCombo</tabstop> - <tabstop>javaScriptGroup</tabstop> <tabstop>jsOpenWindowsCheckBox</tabstop> <tabstop>jsClipboardCheckBox</tabstop> <tabstop>pluginsCheckBox</tabstop> @@ -784,6 +824,7 @@ <tabstop>sendRefererCheckBox</tabstop> <tabstop>refererWhitelistButton</tabstop> <tabstop>xssAuditingCheckBox</tabstop> + <tabstop>insecureContentsCheckBox</tabstop> <tabstop>expireHistory</tabstop> <tabstop>diskCacheCheckBox</tabstop> <tabstop>cacheSizeSpinBox</tabstop> @@ -791,6 +832,8 @@ <tabstop>imageSearchComboBox</tabstop> <tabstop>spatialCheckBox</tabstop> <tabstop>linksInFocusChainCheckBox</tabstop> + <tabstop>focusOnNavigationCheckBox</tabstop> + <tabstop>printBackgroundCheckBox</tabstop> <tabstop>autoScrollGroupBox</tabstop> <tabstop>autoScrollDividerSpinBox</tabstop> <tabstop>webInspectorGroup</tabstop>
--- a/Preferences/__init__.py Sat Feb 18 12:23:35 2017 +0100 +++ b/Preferences/__init__.py Sat Feb 18 19:59:14 2017 +0100 @@ -1066,6 +1066,9 @@ "DownloadManagerSize": QSize(400, 300), "DownloadManagerPosition": QPoint(), "DownloadManagerDownloads": [], + # Spell Checking + "SpellCheckEnabled": False, + "SpellCheckLanguages": [], # Sync "SyncEnabled": False, "SyncBookmarks": True, @@ -1172,11 +1175,18 @@ }) except AttributeError: pass - - # TODO: add these for Qt 5.8+ - # QWebEngineSettings.FocusOnNavigationEnabled - # QWebEngineSettings.PrintElementBackgrounds - # QWebEngineSettings.AllowRunningInsecureContent + try: + # Qt 5.8+ + cls.webBrowserDefaults.update({ + "FocusOnNavigationEnabled": webEngineSettings.testAttribute( + QWebEngineSettings.FocusOnNavigationEnabled), + "PrintElementBackgrounds": webEngineSettings.testAttribute( + QWebEngineSettings.PrintElementBackgrounds), + "AllowRunningInsecureContent": webEngineSettings.testAttribute( + QWebEngineSettings.AllowRunningInsecureContent), + }) + except AttributeError: + pass cls.webEngineSettingsIntitialized = True @@ -2857,12 +2867,15 @@ "AdBlockEnabled", "AdBlockUseLimitedEasyList", "PluginsEnabled", "FullScreenSupportEnabled", "AutoScrollEnabled", "ScreenCaptureEnabled", - "WebGLEnabled", + "WebGLEnabled", "FocusOnNavigationEnabled", + "PrintElementBackgrounds", "AllowRunningInsecureContent", + "SpellCheckEnabled", ]: return toBool(prefClass.settings.value( "WebBrowser/" + key, prefClass.webBrowserDefaults[key])) elif key in ["GreaseMonkeyDisabledScripts", "SendRefererWhitelist", "AdBlockSubscriptions", "AdBlockExceptions", + "SpellCheckLanguages", ]: return toList(prefClass.settings.value( "WebBrowser/" + key, prefClass.helpDefaults[key]))
--- a/WebBrowser/Download/DownloadItem.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/Download/DownloadItem.py Sat Feb 18 19:59:14 2017 +0100 @@ -110,12 +110,17 @@ # reset info self.infoLabel.clear() self.progressBar.setValue(0) - self.__getFileName() - if not self.__fileName: - self.__downloadItem.cancel() + if self.__downloadItem.state() == \ + QWebEngineDownloadItem.DownloadRequested: + self.__getFileName() + if not self.__fileName: + self.__downloadItem.cancel() + else: + self.__downloadItem.setPath(self.__fileName) + self.__downloadItem.accept() else: - self.__downloadItem.setPath(self.__fileName) - self.__downloadItem.accept() + fileName = self.__downloadItem.path() + self.__setFileName(fileName) def __getFileName(self): """ @@ -124,8 +129,10 @@ if self.__gettingFileName: return - # TODO: Qt 5.8 - add support for QWebEngineDownloadItem.DownloadType - if qVersion() >= "5.7.0": + if qVersion() >= "5.8.0": + savePage = self.__downloadItem.type() == \ + QWebEngineDownloadItem.SavePage + elif qVersion() >= "5.7.0": savePage = self.__downloadItem.savePageFormat() != \ QWebEngineDownloadItem.UnknownSaveFormat else: @@ -197,7 +204,7 @@ "") self.__gettingFileName = False else: - # TODO: Qt 5.8 - maybe format selection is not neccessary + # save page file name and format selection for Qt < 5.8.0 self.__autoOpen = False filterList = [ @@ -250,6 +257,15 @@ self.__canceledFileSelect = True return + self.__setFileName(fileName) + + def __setFileName(self, fileName): + """ + Private method to set the file name to save the download into. + + @param fileName name of the file to save into + @type str + """ fileInfo = QFileInfo(fileName) WebBrowserWindow.downloadManager()\ .setDownloadDirectory(fileInfo.absoluteDir().absolutePath()) @@ -443,7 +459,7 @@ else: if self.__bytesReceived == bytesTotal or bytesTotal == -1: info = self.tr("{0} downloaded")\ - .format(dataString(self.__output.size())) + .format(dataString(self.__bytesReceived)) else: info = self.tr("{0} of {1} - Stopped")\ .format(dataString(self.__bytesReceived), @@ -488,8 +504,8 @@ self.stopButton.setVisible(False) self.openButton.setEnabled(noError) self.openButton.setVisible(noError) + self.__state = DownloadItem.DownloadSuccessful self.__updateInfoLabel() - self.__state = DownloadItem.DownloadSuccessful self.statusChanged.emit() self.downloadFinished.emit()
--- a/WebBrowser/Network/SslErrorExceptionsDialog.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/Network/SslErrorExceptionsDialog.py Sat Feb 18 19:59:14 2017 +0100 @@ -77,7 +77,15 @@ except AttributeError: # the value was added in Qt 5.7 pass - # TODO: Qt 5.8 - add support for QWebEngineCertificateError.CertificateTransparencyRequired + try: + self.__errorDescriptions[ + QWebEngineCertificateError.CertificateTransparencyRequired] = \ + self.tr("Certificate Transparency was required for this" + " connection, but the server did not provide" + " information that complied with the policy.") + except AttributeError: + # the value was added in Qt 5.8 + pass for host, errors in errorsDict.items(): itm = QTreeWidgetItem(self.errorsTree, [host])
--- a/WebBrowser/Tools/WebHitTestResult.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/Tools/WebHitTestResult.py Sat Feb 18 19:59:14 2017 +0100 @@ -106,6 +106,31 @@ """.format(self.__viewportPos.x(), self.__viewportPos.y()) self.__populate(page.url(), page.execJavaScript(script)) + def updateWithContextMenuData(self, data): + """ + Public method to update the hit test data with data from the context + menu event. + + Note: This works for Qt >= 5.7.0. + + @param data context menu data + @type QWebEngineContextMenuData + """ + from PyQt5.QtWebEngineWidgets import QWebEngineContextMenuData + if not data.isValid() or data.position() != self.__pos: + return + + self.__linkTitle = data.linkText() + self.__linkUrl = data.linkUrl() + self.__isContentEditable = data.isContentEditable() + self.__isContentSelected = bool(data.selectedText()) + + if data.mediaType() == QWebEngineContextMenuData.MediaTypeImage: + self.__imageUrl = data.mediaUrl() + elif data.mediaType() in [QWebEngineContextMenuData.MediaTypeAudio, + QWebEngineContextMenuData.MediaTypeVideo]: + self.__mediaUrl = data.mediaUrl() + def baseUrl(self): """ Public method to get the base URL of the page.
--- a/WebBrowser/WebBrowserPage.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/WebBrowserPage.py Sat Feb 18 19:59:14 2017 +0100 @@ -62,6 +62,8 @@ self.fullScreenRequested.connect(self.__fullScreenRequested) self.urlChanged.connect(self.__urlChanged) + + self.__printer = None def acceptNavigationRequest(self, url, type_, isMainFrame): """ @@ -308,6 +310,28 @@ else: request.reject() + def printPage(self, printer): + """ + Public method to print the current page. + + Note: This is just a wrapper around QWebEnginePage.print() to ensure + the printer object is available until the print job finished. + + @param printer reference to the printer object + @type QPrinter + """ + self.__printer = printer + self.print(self.__printer, self.__printFinished) + + def __printFinished(self, ok): + """ + Private method called when the print job finished. + + @param ok flag indicating a successful print + @type bool + """ + self.__printer = None + ############################################## ## Methods below deal with JavaScript messages ##############################################
--- a/WebBrowser/WebBrowserTabWidget.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/WebBrowserTabWidget.py Sat Feb 18 19:59:14 2017 +0100 @@ -638,11 +638,14 @@ if FilePrinter.isCupsAvailable(): printDialog.setOption(QAbstractPrintDialog.PrintCollateCopies) printDialog.setOption(QAbstractPrintDialog.PrintPageRange) - # TODO: Add Qt 5.8 print support if printDialog.exec_() == QDialog.Accepted: - if not hasattr(browser.page(), "printToPdf"): - browser.render(printer) - else: + # TODO: enable this once it works correctly in Qt +## if hasattr(browser.page(), "print"): +## # Qt >= 5.8.0 +## browser.page().printPage(printer) +## elif hasattr(browser.page(), "printToPdf"): + if hasattr(browser.page(), "printToPdf"): + # Qt >= 5.7.0 if printer.outputFormat() == QPrinter.PdfFormat: # print to PDF file selected browser.page().printToPdf( @@ -655,6 +658,8 @@ browser.page().printToPdf( self.__pdfGeneratedForPrinting, printer.pageLayout()) + else: + browser.render(printer) @pyqtSlot() def printBrowserPdf(self, browser=None):
--- a/WebBrowser/WebBrowserView.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/WebBrowserView.py Sat Feb 18 19:59:14 2017 +0100 @@ -17,13 +17,14 @@ import os from PyQt5.QtCore import pyqtSignal, QUrl, QFileInfo, Qt, QTimer, QEvent, \ - QPoint, QDateTime, qVersion + QPoint, QDateTime, qVersion, QStandardPaths from PyQt5.QtGui import QDesktopServices, QClipboard, QIcon, \ QContextMenuEvent, QPixmap from PyQt5.QtWidgets import qApp, QStyle, QMenu, QApplication -from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage +from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage, \ + QWebEngineDownloadItem -from E5Gui import E5MessageBox +from E5Gui import E5MessageBox, E5FileDialog from WebBrowser.WebBrowserWindow import WebBrowserWindow from .WebBrowserPage import WebBrowserPage @@ -503,6 +504,28 @@ @type WebHitTestResult """ # TODO: Qt 5.8 - add support for spell checking + spellCheckActionCount = 0 + if qVersion() >= "5.7.0": + contextMenuData = self.page().contextMenuData() + hitTest.updateWithContextMenuData(contextMenuData) + + if qVersion() >= "5.8.0" and \ + bool(contextMenuData.misspelledWord()): + boldFont = menu.font() + boldFont.setBold(True) + + for suggestion in contextMenuData.spellCheckerSuggestions(): + act = menu.addAction( + suggestion, + lambda: self.page().replaceMisspelledWord(suggestion)) + act.setFont(boldFont) + + if bool(menu.actions()): + menu.addAction(self.tr("No suggestions")).setEnabled(False) + + menu.addSeparator() + spellCheckActionCount = len(menu.actions()) + if not hitTest.linkUrl().isEmpty() and \ hitTest.linkUrl().scheme() != "javascript": self.__createLinkContextMenu(menu, hitTest) @@ -514,15 +537,17 @@ self.__createMediaContextMenu(menu, hitTest) if hitTest.isContentEditable(): - menu.addAction(self.__mw.undoAct) - menu.addAction(self.__mw.redoAct) - menu.addSeparator() - menu.addAction(self.__mw.cutAct) - menu.addAction(self.__mw.copyAct) - menu.addAction(self.__mw.pasteAct) - menu.addSeparator() - self.__mw.personalInformationManager().createSubMenu( - menu, self, hitTest) + # check, if only spell checker actions were added + if len(menu.actions()) == spellCheckActionCount: + menu.addAction(self.__mw.undoAct) + menu.addAction(self.__mw.redoAct) + menu.addSeparator() + menu.addAction(self.__mw.cutAct) + menu.addAction(self.__mw.copyAct) + menu.addAction(self.__mw.pasteAct) + menu.addSeparator() + self.__mw.personalInformationManager().createSubMenu( + menu, self, hitTest) if hitTest.tagName() == "input": menu.addSeparator() @@ -1340,7 +1365,6 @@ """ # find the render widget receiving events for the web page if obj is self and evt.type() == QEvent.ChildAdded: - # TODO: Qt 5.8 - check, if this still works on 5.8 (see Qupzilla) child = evt.child() if child and child.inherits( "QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget"): @@ -1615,8 +1639,76 @@ if url.isEmpty(): return - # TODO: Qt 5.8 - use QWebEnginePage.save() - self.triggerPageAction(QWebEnginePage.SavePage) + if qVersion() >= "5.8.0": + # since Qt 5.8.0 + fileName, savePageFormat = self.__getSavePageFileNameAndFormat() + if fileName: + self.page().save(fileName, savePageFormat) + else: + self.triggerPageAction(QWebEnginePage.SavePage) + + def __getSavePageFileNameAndFormat(self): + """ + Private method to get the file name to save the page to. + + @return tuple containing the file name to save to and the + save page format + @rtype tuple of (str, QWebEngineDownloadItem.SavePageFormat) + """ + documentLocation = QStandardPaths.writableLocation( + QStandardPaths.DocumentsLocation) + filterList = [ + self.tr("Web Archive (*.mhtml *.mht)"), + self.tr("HTML File (*.html *.htm)"), + self.tr("HTML File with all resources (*.html *.htm)"), + ] + extensionsList = [ + # tuple of extensions for *nix and Windows + # keep in sync with filters list + (".mhtml", ".mht"), + (".html", ".htm"), + (".html", ".htm"), + ] + if self.url().fileName(): + defaultFileName = os.path.join(documentLocation, + self.url().fileName()) + else: + defaultFileName = os.path.join(documentLocation, + self.page().title()) + if Utilities.isWindowsPlatform(): + defaultFileName += ".mht" + else: + defaultFileName += ".mhtml" + + fileName = "" + saveFormat = QWebEngineDownloadItem.MimeHtmlSaveFormat + + fileName, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( + None, + self.tr("Save Web Page"), + defaultFileName, + ";;".join(filterList), + None) + if fileName: + index = filterList.index(selectedFilter) + if index == 0: + saveFormat = QWebEngineDownloadItem.MimeHtmlSaveFormat + elif index == 1: + saveFormat = QWebEngineDownloadItem.SingleHtmlSaveFormat + else: + saveFormat = QWebEngineDownloadItem.CompleteHtmlSaveFormat + + extension = os.path.splitext(fileName)[1] + if not extension: + # add the platform specific default extension + if Utilities.isWindowsPlatform(): + extensionsIndex = 1 + else: + extensionsIndex = 0 + extensions = extensionsList[index] + fileName += extensions[extensionsIndex] + + return fileName, saveFormat ########################################################################### ## Miscellaneous methods below
--- a/WebBrowser/WebBrowserWindow.py Sat Feb 18 12:23:35 2017 +0100 +++ b/WebBrowser/WebBrowserWindow.py Sat Feb 18 19:59:14 2017 +0100 @@ -62,7 +62,6 @@ from eric6config import getConfig -# TODO: Qt 5.8 - support spell checking through out class WebBrowserWindow(E5MainWindow): """ Class implementing the web browser main window. @@ -529,6 +528,20 @@ Preferences.getWebBrowser("WebGLEnabled")) except (AttributeError, KeyError): pass + + try: + # Qt 5.8 + settings.setAttribute( + QWebEngineSettings.FocusOnNavigationEnabled, + Preferences.getWebBrowser("FocusOnNavigationEnabled")) + settings.setAttribute( + QWebEngineSettings.PrintElementBackgrounds, + Preferences.getWebBrowser("PrintElementBackgrounds")) + settings.setAttribute( + QWebEngineSettings.AllowRunningInsecureContent, + Preferences.getWebBrowser("AllowRunningInsecureContent")) + except (AttributeError, KeyError): + pass def __initActions(self): """ @@ -2817,8 +2830,8 @@ self.autoScroller().preferencesChanged() + profile = self.webProfile() if not self.isPrivate(): - profile = self.webProfile() if Preferences.getWebBrowser("DiskCacheEnabled"): profile.setHttpCacheType(QWebEngineProfile.DiskHttpCache) profile.setHttpCacheMaximumSize( @@ -2826,7 +2839,13 @@ else: profile.setHttpCacheType(QWebEngineProfile.MemoryHttpCache) profile.setHttpCacheMaximumSize(0) - + + if qVersion() >= "5.8.0": + profile.setSpellCheckEnabled( + Preferences.getWebBrowser("SpellCheckEnabled")) + profile.setSpellCheckLanguages( + Preferences.getWebBrowser("SpellCheckLanguages")) + self.__virusTotal.preferencesChanged() if not Preferences.getWebBrowser("VirusTotalEnabled") or \ Preferences.getWebBrowser("VirusTotalServiceKey") == "": @@ -4225,6 +4244,13 @@ cls._webProfile.setPersistentCookiesPolicy( QWebEngineProfile.AllowPersistentCookies) + # TODO: Qt 5.8 - add support for spell checking + if qVersion() >= "5.8.0": + cls._webProfile.setSpellCheckEnabled( + Preferences.getWebBrowser("SpellCheckEnabled")) + cls._webProfile.setSpellCheckLanguages( + Preferences.getWebBrowser("SpellCheckLanguages")) + # Setup QWebChannel user script from .WebBrowserPage import WebBrowserPage