Thu, 06 Aug 2015 19:01:39 +0200
Started to implement the HTML5 feature permission manager and associated dialogs.
--- a/Helpviewer/FeaturePermissionBar.py Wed Aug 05 19:52:39 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing the feature permission bar widget. -""" - -from __future__ import unicode_literals - -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtWidgets import QLabel, QHBoxLayout, QPushButton -from PyQt5.QtWebKitWidgets import QWebFrame, QWebPage - -from E5Gui.E5AnimatedWidget import E5AnimatedWidget - -import UI.PixmapCache - - -class FeaturePermissionBar(E5AnimatedWidget): - """ - Class implementing the feature permission bar widget. - """ - featurePermissionProvided = pyqtSignal(QWebFrame, QWebPage.Feature, - QWebPage.PermissionPolicy) - - DefaultHeight = 30 - - def __init__(self, view, frame, feature): - """ - Constructor - - @param view reference to the web view - @type QWebView - @param frame frame sending the request - @type QWebFrame - @param feature requested feature - @type QWebPage.Feature - """ - super(FeaturePermissionBar, self).__init__(parent=view) - - self.__messageLabel = QLabel(self) - - self.__frame = frame - self.__feature = feature - - self.__permissionFeatureTexts = { - QWebPage.Notifications: - self.tr("{0} wants to use desktop notifications."), - QWebPage.Geolocation: - self.tr("{0} wants to use your position.") - } - - self.setAutoFillBackground(True) - self.__layout = QHBoxLayout() - self.setLayout(self.__layout) - self.__layout.setContentsMargins(self.DefaultHeight, 0, 0, 0) - self.__layout.addWidget(self.__messageLabel) - self.__layout.addStretch() - self.__allowButton = QPushButton(self.tr("Allow"), self) - self.__denyButton = QPushButton(self.tr("Deny"), self) - self.__discardButton = QPushButton(UI.PixmapCache.getIcon("close.png"), - "", self) - self.__allowButton.clicked.connect(self.__permissionGranted) - self.__denyButton.clicked.connect(self.__permissionDenied) - self.__discardButton.clicked.connect(self.__permissionUnknown) - self.__layout.addWidget(self.__allowButton) - self.__layout.addWidget(self.__denyButton) - self.__layout.addWidget(self.__discardButton) - - try: - self.__messageLabel.setText( - self.__permissionFeatureTexts[self.__feature].format( - self.__frame.securityOrigin().host())) - except KeyError: - self.__messageLabel.setText( - self.tr("{0} wants to use an unknown feature.").format( - self.__frame.securityOrigin().host())) - - self.resize(view.width(), self.height()) - self.startAnimation() - - def __permissionDenied(self): - """ - Private slot handling the user pressing the deny button. - """ - self.featurePermissionProvided.emit(self.__frame, self.__feature, - QWebPage.PermissionDeniedByUser) - self.hide() - - def __permissionGranted(self): - """ - Private slot handling the user pressing the allow button. - """ - self.featurePermissionProvided.emit(self.__frame, self.__feature, - QWebPage.PermissionGrantedByUser) - self.hide() - - def __permissionUnknown(self): - """ - Private slot handling the user closing the dialog without. - """ - self.featurePermissionProvided.emit(self.__frame, self.__feature, - QWebPage.PermissionUnknown) - self.hide()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Helpviewer/FeaturePermissions/FeaturePermissionBar.py Thu Aug 06 19:01:39 2015 +0200 @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the feature permission bar widget. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot +from PyQt5.QtWidgets import QLabel, QHBoxLayout, QPushButton, QCheckBox +from PyQt5.QtWebKitWidgets import QWebPage + +from E5Gui.E5AnimatedWidget import E5AnimatedWidget + +import Helpviewer + +import UI.PixmapCache + + +class FeaturePermissionBar(E5AnimatedWidget): + """ + Class implementing the feature permission bar widget. + """ + DefaultHeight = 30 + + def __init__(self, view, frame, feature): + """ + Constructor + + @param view reference to the web view + @type QWebView + @param frame frame sending the request + @type QWebFrame + @param feature requested feature + @type QWebPage.Feature + """ + super(FeaturePermissionBar, self).__init__(parent=view) + + self.__messageLabel = QLabel(self) + + self.__frame = frame + self.__feature = feature + self.__view = view + + self.__permissionFeatureTexts = { + QWebPage.Notifications: + self.tr("{0} wants to use desktop notifications."), + QWebPage.Geolocation: + self.tr("{0} wants to use your position.") + } + + self.setAutoFillBackground(True) + self.__layout = QHBoxLayout() + self.setLayout(self.__layout) + self.__layout.setContentsMargins(self.DefaultHeight, 0, 0, 0) + self.__layout.addWidget(self.__messageLabel) + self.__layout.addStretch() + self.__rememberCheckBox = QCheckBox(self.tr("Remember"), self) + self.__layout.addWidget(self.__rememberCheckBox) + self.__allowButton = QPushButton(self.tr("Allow"), self) + self.__denyButton = QPushButton(self.tr("Deny"), self) + self.__discardButton = QPushButton(UI.PixmapCache.getIcon("close.png"), + "", self) + self.__allowButton.clicked.connect(self.__permissionGranted) + self.__denyButton.clicked.connect(self.__permissionDenied) + self.__discardButton.clicked.connect(self.__permissionUnknown) + self.__layout.addWidget(self.__allowButton) + self.__layout.addWidget(self.__denyButton) + self.__layout.addWidget(self.__discardButton) + + try: + self.__messageLabel.setText( + self.__permissionFeatureTexts[self.__feature].format( + self.__frame.securityOrigin().host())) + except KeyError: + self.__messageLabel.setText( + self.tr("{0} wants to use an unknown feature.").format( + self.__frame.securityOrigin().host())) + + self.__view.page().loadStarted.connect(self.hide) + + self.resize(view.width(), self.height()) + self.startAnimation() + + @pyqtSlot() + def hide(self): + """ + Public slot to hide the animated widget. + """ + self.__view.page().loadStarted.disconnect(self.hide) + super(FeaturePermissionBar, self).hide() + + def __permissionDenied(self): + """ + Private slot handling the user pressing the deny button. + """ + if self.__frame is None or self.__frame.page() is None: + return + + page = self.__frame.page() + page.setFeaturePermission(self.__frame, self.__feature, + QWebPage.PermissionDeniedByUser) + + if self.__rememberCheckBox.isChecked(): + Helpviewer.HelpWindow.HelpWindow.featurePermissionManager()\ + .rememberFeaturePermission(page.url().host(), self.__feature, + QWebPage.PermissionDeniedByUser) + + self.hide() + + def __permissionGranted(self): + """ + Private slot handling the user pressing the allow button. + """ + if self.__frame is None or self.__frame.page() is None: + return + + page = self.__frame.page() + page.setFeaturePermission(self.__frame, self.__feature, + QWebPage.PermissionGrantedByUser) + + if self.__rememberCheckBox.isChecked(): + Helpviewer.HelpWindow.HelpWindow.featurePermissionManager()\ + .rememberFeaturePermission(page.url().host(), self.__feature, + QWebPage.PermissionGrantedByUser) + + self.hide() + + def __permissionUnknown(self): + """ + Private slot handling the user closing the dialog without. + """ + if self.__frame is None or self.__frame.page() is None: + return + + page = self.__frame.page() + page.setFeaturePermission(self.__frame, self.__feature, + QWebPage.PermissionUnknown) + self.hide()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Helpviewer/FeaturePermissions/FeaturePermissionManager.py Thu Aug 06 19:01:39 2015 +0200 @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the feature permission manager object. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QObject +from PyQt5.QtWebKitWidgets import QWebPage + +import Globals +import Preferences + + +class FeaturePermissionManager(QObject): + """ + Class implementing the feature permission manager object. + """ + SettingsKeyFormat = "Help/FeaturePermissions/{0}" + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object + @type QObject + """ + super(FeaturePermissionManager, self).__init__(parent) + + self.__featurePermissions = { + QWebPage.Notifications: { + QWebPage.PermissionGrantedByUser: [], + QWebPage.PermissionDeniedByUser: [], + }, + QWebPage.Geolocation: { + QWebPage.PermissionGrantedByUser: [], + QWebPage.PermissionDeniedByUser: [], + }, + } + self.__featurePermissionsKeys = { + (QWebPage.Notifications, QWebPage.PermissionGrantedByUser): + "NotificationsGranted", + (QWebPage.Notifications, QWebPage.PermissionDeniedByUser): + "NotificationsDenied", + (QWebPage.Geolocation, QWebPage.PermissionGrantedByUser): + "GeolocationGranted", + (QWebPage.Geolocation, QWebPage.PermissionDeniedByUser): + "GeolocationDenied", + } + + self.__loaded = False + + def requestFeaturePermission(self, page, frame, feature): + """ + Private method to request a feature permission. + + @param page reference to the requesting web page + @type QWebPage + @param frame frame sending the request + @type QWebFrame + @param feature requested feature + @type QWebPage.Feature + """ + if page is None or frame is None: + return + + if not self.__loaded: + self.__loadSettings() + + host = page.url().host() + + if feature in self.__featurePermissions: + for permission in self.__featurePermissions[feature]: + if host in self.__featurePermissions[feature][permission]: + page.setFeaturePermission(frame, feature, permission) + return + + view = page.view() + if view is not None: + from .FeaturePermissionBar import FeaturePermissionBar + bar = FeaturePermissionBar(view, frame, feature) + bar.show() + + def rememberFeaturePermission(self, host, feature, permission): + """ + Public method to remember a user decision for a feature permission. + + @param host host name to remember the decision for + @type str + @param feature feature to be remembered + @type QWebPage.Feature + @param permission feature permission to be remembered + @type QWebPage.PermissionPolicy + """ + if feature in self.__featurePermissions: + if host not in self.__featurePermissions[feature][permission]: + self.__featurePermissions[feature][permission].append(host) + self.__saveSettings() + + def __loadSettings(self): + """ + Private method to load the remembered feature permissions. + """ + if self.__loaded: + # no reloading allowed + return + + for (feature, permission), key in \ + self.__featurePermissionsKeys.items(): + self.__featurePermissions[feature][permission] = \ + Globals.toList(Preferences.Prefs.settings.value( + FeaturePermissionManager.SettingsKeyFormat.format(key), + [] + )) + + self.__loaded = True + + def __saveSettings(self): + """ + Private method to save the remembered feature permissions. + """ + if not self.__loaded: + return + + for (feature, permission), key in \ + self.__featurePermissionsKeys.items(): + Preferences.Prefs.settings.setValue( + FeaturePermissionManager.SettingsKeyFormat.format(key), + self.__featurePermissions[feature][permission]) + + def showFeaturePermissionsDialog(self): + """ + Public method to show a dialog to manage the remembered feature + permissions. + """ + # TODO: implement this + pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Helpviewer/FeaturePermissions/__init__.py Thu Aug 06 19:01:39 2015 +0200 @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing feature permission related widgets for the eric6 +web browser. +"""
--- a/Helpviewer/HelpBrowserWV.py Wed Aug 05 19:52:39 2015 +0200 +++ b/Helpviewer/HelpBrowserWV.py Thu Aug 06 19:01:39 2015 +0200 @@ -33,6 +33,8 @@ from E5Gui import E5MessageBox, E5FileDialog +import Helpviewer + import Preferences import UI.PixmapCache import Globals @@ -768,11 +770,8 @@ self.page().setForwardUnsupportedContent(True) self.page().unsupportedContent.connect(self.__unsupportedContent) - self.__featurePermissionBar = None self.page().featurePermissionRequested.connect( self.__featurePermissionRequested) - # discard the feature bar on new loads (if we navigate away or reload) - self.page().loadStarted.connect(self.__featurePermissionBarDelete) self.page().downloadRequested.connect(self.__downloadRequested) self.page().frameCreated.connect(self.__addExternalBinding) @@ -2124,35 +2123,8 @@ @param feature requested feature @type QWebPage.Feature """ - from .FeaturePermissionBar import FeaturePermissionBar - self.__featurePermissionBar = FeaturePermissionBar(self, frame, - feature) - self.__featurePermissionBar.featurePermissionProvided.connect( - self.__setFeaturePermission) - self.__featurePermissionBar.show() - - def __setFeaturePermission(self, frame, feature, policy): - """ - Private slot to set the feature permissions. - - @param frame frame to set the permission for - @type QWebFrame - @param feature feature to set permission for - @type QWebPage.Feature - @param policy permission policy to be set - @type QWebPage.PermissionPolicy - """ - self.page().setFeaturePermission(frame, feature, policy) - self.__featurePermissionBarDelete() - - def __featurePermissionBarDelete(self): - """ - Private slot to delete the feature permission bar. - """ - if self.__featurePermissionBar is not None: - self.__featurePermissionBar.deleteLater() - self.__featurePermissionBar.hide() - self.__featurePermissionBar = None + manager = Helpviewer.HelpWindow.HelpWindow.featurePermissionManager() + manager.requestFeaturePermission(self.page(), frame, feature) def __downloadRequested(self, request): """
--- a/Helpviewer/HelpWindow.py Wed Aug 05 19:52:39 2015 +0200 +++ b/Helpviewer/HelpWindow.py Thu Aug 06 19:01:39 2015 +0200 @@ -88,6 +88,7 @@ _personalInformationManager = None _greaseMonkeyManager = None _notification = None + _featurePermissionManager = None def __init__(self, home, path, parent, name, fromEric=False, initShortcutsOnly=False, searchWord=None): @@ -1195,6 +1196,23 @@ E5ErrorMessage.editMessageFilters) self.__actions.append(self.editMessageFilterAct) + self.featurePermissionAct = E5Action( + self.tr('Edit HTML5 Feature Permissions'), + UI.PixmapCache.getIcon("featurePermission.png"), + self.tr('Edit HTML5 Feature Permissions...'), 0, 0, self, + 'help_edit_feature_permissions') + self.featurePermissionAct.setStatusTip(self.tr( + 'Edit the remembered HTML5 feature permissions')) + self.featurePermissionAct.setWhatsThis(self.tr( + """<b>Edit HTML5 Feature Permissions</b>""" + """<p>Opens a dialog to edit the remembered HTML5""" + """ feature permissions.</p>""" + )) + if not self.initShortcutsOnly: + self.featurePermissionAct.triggered.connect( + self.__showFeaturePermissionDialog) + self.__actions.append(self.featurePermissionAct) + if self.useQtHelp or self.initShortcutsOnly: self.syncTocAct = E5Action( self.tr('Sync with Table of Contents'), @@ -1632,6 +1650,7 @@ menu.addAction(self.offlineStorageAct) menu.addAction(self.personalDataAct) menu.addAction(self.greaseMonkeyAct) + menu.addAction(self.featurePermissionAct) menu.addSeparator() menu.addAction(self.editMessageFilterAct) menu.addSeparator() @@ -1761,6 +1780,7 @@ settingstb.addAction(self.offlineStorageAct) settingstb.addAction(self.personalDataAct) settingstb.addAction(self.greaseMonkeyAct) + settingstb.addAction(self.featurePermissionAct) toolstb = self.addToolBar(self.tr("Tools")) toolstb.setObjectName("ToolsToolBar") @@ -3051,6 +3071,12 @@ """ self.greaseMonkeyManager().showConfigurationDialog() + def __showFeaturePermissionDialog(self): + """ + Private slot to show the feature permission dialog. + """ + self.featurePermissionManager().showFeaturePermissionsDialog() + def __showNetworkMonitor(self): """ Private slot to show the network monitor dialog. @@ -3260,6 +3286,21 @@ return cls._greaseMonkeyManager @classmethod + def featurePermissionManager(cls): + """ + Class method to get a reference to the feature permission manager. + + @return reference to the feature permission manager + @rtype FeaturePermissionManager + """ + if cls._featurePermissionManager is None: + from .FeaturePermissions.FeaturePermissionManager import \ + FeaturePermissionManager + cls._featurePermissionManager = FeaturePermissionManager() + + return cls._featurePermissionManager + + @classmethod def mainWindow(cls): """ Class method to get a reference to the main window.
--- a/eric6.e4p Wed Aug 05 19:52:39 2015 +0200 +++ b/eric6.e4p Thu Aug 06 19:01:39 2015 +0200 @@ -304,7 +304,9 @@ <Source>Helpviewer/Download/DownloadModel.py</Source> <Source>Helpviewer/Download/DownloadUtilities.py</Source> <Source>Helpviewer/Download/__init__.py</Source> - <Source>Helpviewer/FeaturePermissionBar.py</Source> + <Source>Helpviewer/FeaturePermissions/FeaturePermissionBar.py</Source> + <Source>Helpviewer/FeaturePermissions/FeaturePermissionManager.py</Source> + <Source>Helpviewer/FeaturePermissions/__init__.py</Source> <Source>Helpviewer/Feeds/FeedEditDialog.py</Source> <Source>Helpviewer/Feeds/FeedsDialog.py</Source> <Source>Helpviewer/Feeds/FeedsManager.py</Source>