Started to implement the HTML5 feature permission manager and associated dialogs.

Thu, 06 Aug 2015 19:01:39 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 06 Aug 2015 19:01:39 +0200
changeset 4355
40ec6bef4c22
parent 4354
bc2b247a75df
child 4356
975993ebd7fb

Started to implement the HTML5 feature permission manager and associated dialogs.

Helpviewer/FeaturePermissionBar.py file | annotate | diff | comparison | revisions
Helpviewer/FeaturePermissions/FeaturePermissionBar.py file | annotate | diff | comparison | revisions
Helpviewer/FeaturePermissions/FeaturePermissionManager.py file | annotate | diff | comparison | revisions
Helpviewer/FeaturePermissions/__init__.py file | annotate | diff | comparison | revisions
Helpviewer/HelpBrowserWV.py file | annotate | diff | comparison | revisions
Helpviewer/HelpWindow.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
icons/default/featurePermission.png file | annotate | diff | comparison | revisions
--- 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>
Binary file icons/default/featurePermission.png has changed

eric ide

mercurial