eric6/Helpviewer/WebPlugins/ClickToFlash/ClickToFlash.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
diff -r f99d60d6b59b -r 2602857055c5 eric6/Helpviewer/WebPlugins/ClickToFlash/ClickToFlash.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Helpviewer/WebPlugins/ClickToFlash/ClickToFlash.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,321 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the Flash blocker.
+"""
+
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSlot, QUrl, Qt, QByteArray, QTimer
+from PyQt5.QtGui import QCursor
+from PyQt5.QtWidgets import QWidget, QMenu, QDialog, QLabel, QFormLayout
+from PyQt5.QtNetwork import QNetworkRequest
+from PyQt5.QtWebKit import QWebElement, QWebElementCollection
+from PyQt5.QtWebKitWidgets import QWebHitTestResult, QWebView
+
+from .Ui_ClickToFlash import Ui_ClickToFlash
+
+import UI.PixmapCache
+
+
+class ClickToFlash(QWidget, Ui_ClickToFlash):
+    """
+    Class implementing the Flash blocker.
+    """
+    _acceptedUrl = QUrl()
+    _acceptedArgNames = []
+    _acceptedArgValues = []
+
+    def __init__(self, plugin, mimeType, url, argumentNames, argumentValues,
+                 parent=None):
+        """
+        Constructor
+        
+        @param plugin reference to the plug-in (ClickToFlashPlugin)
+        @param mimeType MIME type for the plug-in (string)
+        @param url requested URL (QUrl)
+        @param argumentNames list of argument names (list of strings)
+        @param argumentValues list of argument values (list of strings)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(ClickToFlash, self).__init__(parent)
+        
+        # Check AdBlock first
+        import Helpviewer.HelpWindow
+        manager = Helpviewer.HelpWindow.HelpWindow.adBlockManager()
+        if manager.isEnabled():
+            urlString = bytes(url.toEncoded()).decode()
+            urlDomain = url.host()
+            for subscription in manager.subscriptions():
+                blockedRule = subscription.match(
+                    QNetworkRequest(url), urlDomain, urlString)
+                if blockedRule:
+                    QTimer.singleShot(200, self.__hideAdBlocked)
+                    return
+        
+        self.setupUi(self)
+        
+        self.__swapping = False
+        self.__element = QWebElement()
+        
+        self.__plugin = plugin
+        self.__url = QUrl(url)
+        self.__argumentNames = argumentNames[:]
+        self.__argumentValues = argumentValues[:]
+        self.__mimeType = mimeType
+        
+        self.setContextMenuPolicy(Qt.CustomContextMenu)
+        self.customContextMenuRequested.connect(self.__showContextMenu)
+        self.setToolTip(self.__url.toString())
+        
+        iconName = plugin.getIconName(mimeType)
+        if iconName:
+            self.loadFlashButton.setIcon(UI.PixmapCache.getIcon(iconName))
+        else:
+            self.loadFlashButton.setText(self.tr("Load"))
+    
+    @pyqtSlot()
+    def on_loadFlashButton_clicked(self):
+        """
+        Private slot handling the flash activation.
+        """
+        self.__load()
+    
+    def __showContextMenu(self):
+        """
+        Private slot to show the context menu.
+        """
+        menu = QMenu()
+        act = menu.addAction(self.tr("Object blocked by ClickToFlash"))
+        font = act.font()
+        font.setBold(True)
+        act.setFont(font)
+        menu.addAction(
+            self.tr("Show information about object"), self.__showInfo)
+        menu.addSeparator()
+        menu.addAction(self.tr("Load"), self.__load)
+        menu.addAction(self.tr("Delete object"), self.__hideAdBlocked)
+        menu.addSeparator()
+        host = self.__url.host()
+        add = menu.addAction(
+            self.tr("Add '{0}' to Whitelist").format(host),
+            self.__addToWhitelist)
+        remove = menu.addAction(
+            self.tr("Remove '{0}' from Whitelist").format(host),
+            self.__removeFromWhitelist)
+        onWhitelist = self.__plugin.onWhitelist(host)
+        add.setEnabled(not onWhitelist)
+        remove.setEnabled(onWhitelist)
+        menu.addSeparator()
+        menu.addAction(self.tr("Configure Whitelist"), self.__configure)
+        menu.actions()[0].setEnabled(False)
+        
+        menu.exec_(QCursor.pos())
+    
+    def swapping(self):
+        """
+        Public method to check, if the plug-in is swapping.
+        
+        @return flag indicating the swapping status (boolean)
+        """
+        return self.__swapping
+    
+    def __configure(self):
+        """
+        Private slot to configure the whitelist.
+        """
+        self.__plugin.configure()
+    
+    def __addToWhitelist(self):
+        """
+        Private slot to add the host to the whitelist.
+        """
+        self.__plugin.addToWhitelist(self.__url.host())
+    
+    def __removeFromWhitelist(self):
+        """
+        Private slot to remove the host from the whitelist.
+        """
+        self.__plugin.removeFromWhitelist(self.__url.host())
+    
+    def __load(self, allPlayers=False):
+        """
+        Private slot to load the flash content.
+        
+        @param allPlayers flag indicating to load all flash players (boolean)
+        """
+        self.__findElement()
+        if not self.__element.isNull():
+            substitute = self.__element.clone()
+            substitute.setAttribute("type", self.__mimeType)
+            self.__element.replace(substitute)
+
+            ClickToFlash._acceptedUrl = self.__url
+            ClickToFlash._acceptedArgNames = self.__argumentNames
+            ClickToFlash._acceptedArgValues = self.__argumentValues
+    
+    def __findElement(self):
+        """
+        Private method to find the element belonging to this ClickToFlash
+        instance.
+        """
+        parent = self.parentWidget()
+        view = None
+        while parent is not None:
+            if isinstance(parent, QWebView):
+                view = parent
+                break
+            parent = parent.parentWidget()
+        if view is None:
+            return
+        
+        objectPos = view.mapFromGlobal(self.loadFlashButton.mapToGlobal(
+            self.loadFlashButton.pos()))
+        objectFrame = view.page().frameAt(objectPos)
+        hitResult = QWebHitTestResult()
+        hitElement = QWebElement()
+        
+        if objectFrame is not None:
+            hitResult = objectFrame.hitTestContent(objectPos)
+            hitElement = hitResult.element()
+        
+        if not hitElement.isNull() and \
+           hitElement.tagName().lower() in ["embed", "object"]:
+            self.__element = hitElement
+            return
+        
+        # hit test failed, trying to find element by src
+        # attribute in elements of all frames on page (although less accurate
+        frames = []
+        frames.append(view.page().mainFrame())
+        while frames:
+            frame = frames.pop(0)
+            if not frame:
+                continue
+            docElement = frame.documentElement()
+            elements = QWebElementCollection()
+            elements.append(docElement.findAll("embed"))
+            elements.append(docElement.findAll("object"))
+            
+            for element in elements:
+                if not self.__checkElement(element) and \
+                   not self.__checkUrlOnElement(element, view):
+                    continue
+                self.__element = element
+                return
+            frames.extend(frame.childFrames())
+    
+    def __checkUrlOnElement(self, element, view):
+        """
+        Private slot to check the URL of an element.
+        
+        @param element reference to the element to check (QWebElement)
+        @param view reference to the view object (QWebView)
+        @return flag indicating a positive result (boolean)
+        """
+        checkString = element.attribute("src")
+        if checkString == "":
+            checkString = element.attribute("data")
+        if checkString == "":
+            checkString = element.attribute("value")
+        
+        checkString = view.url().resolved(QUrl(checkString)).toString(
+            QUrl.RemoveQuery)
+        return self.__url.toEncoded().contains(
+            QByteArray(checkString.encode("utf-8")))
+    
+    def __checkElement(self, element):
+        """
+        Private slot to check an element against the saved arguments.
+        
+        @param element reference to the element to check (QWebElement)
+        @return flag indicating a positive result (boolean)
+        """
+        if self.__argumentNames == element.attributeNames():
+            for name in self.__argumentNames:
+                if element.attribute(name) not in self.__argumentValues:
+                    return False
+            
+            return True
+        
+        return False
+    
+    def __hideAdBlocked(self):
+        """
+        Private slot to hide the object.
+        """
+        self.__findElement()
+        if not self.__element.isNull():
+            self.__element.setStyleProperty("display", "none")
+        else:
+            self.hide()
+    
+    def __showInfo(self):
+        """
+        Private slot to show information about the blocked object.
+        """
+        dlg = QDialog()
+        dlg.setWindowTitle(self.tr("Flash Object"))
+        dlg.setSizeGripEnabled(True)
+        layout = QFormLayout(dlg)
+        layout.addRow(QLabel(self.tr("<b>Attribute Name</b>")),
+                      QLabel(self.tr("<b>Value</b>")))
+        
+        index = 0
+        for name in self.__argumentNames:
+            nameLabel = QLabel(self.__elide(name, length=30))
+            value = self.__argumentValues[index]
+            valueLabel = QLabel(self.__elide(value, length=60))
+            valueLabel.setTextInteractionFlags(
+                Qt.TextSelectableByMouse | Qt.LinksAccessibleByMouse)
+            layout.addRow(nameLabel, valueLabel)
+            
+            index += 1
+        
+        if index == 0:
+            layout.addRow(QLabel(self.tr("No information available.")))
+        
+        dlg.setMaximumHeight(500)
+        dlg.setMaximumWidth(500)
+        dlg.exec_()
+    
+    def __elide(self, txt, mode=Qt.ElideMiddle, length=40):
+        """
+        Private method to elide some text.
+        
+        @param txt text to be elided (string)
+        @keyparam mode elide mode (Qt.TextElideMode)
+        @keyparam length amount of characters to be used (integer)
+        @return the elided text (string)
+        """
+        if mode == Qt.ElideNone or len(txt) < length:
+            return txt
+        elif mode == Qt.ElideLeft:
+            return "...{0}".format(txt[-length:])
+        elif mode == Qt.ElideMiddle:
+            return "{0}...{1}".format(txt[:length // 2], txt[-(length // 2):])
+        elif mode == Qt.ElideRight:
+            return "{0}...".format(txt[:length])
+        else:
+            # just in case
+            return txt
+    
+    @classmethod
+    def isAlreadyAccepted(cls, url, argumentNames, argumentValues):
+        """
+        Class method to check, if the given parameter combination is being
+        accepted.
+        
+        @param url URL to be checked for (QUrl)
+        @param argumentNames argument names to be checked for (list of strings)
+        @param argumentValues argument values to be checked for (list of
+            strings)
+        @return flag indicating that this was already accepted (boolean)
+        """
+        return url == cls._acceptedUrl and \
+            argumentNames == cls._acceptedArgNames and \
+            argumentValues == cls._acceptedArgValues

eric ide

mercurial