src/eric7/WebBrowser/Tools/WebIconProvider.py

Wed, 13 Jul 2022 14:55:47 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 13 Jul 2022 14:55:47 +0200
branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
permissions
-rw-r--r--

Reformatted the source code using the 'Black' utility.

# -*- coding: utf-8 -*-

# Copyright (c) 2016 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module containing a web site icon storage object.
"""

import json
import os
import contextlib

from PyQt6.QtCore import pyqtSignal, QObject, QByteArray, QBuffer, QIODevice, QUrl
from PyQt6.QtGui import QIcon, QPixmap, QImage
from PyQt6.QtWidgets import QDialog

from Utilities.AutoSaver import AutoSaver

import UI.PixmapCache


class WebIconProvider(QObject):
    """
    Class implementing a web site icon storage.

    @signal changed() emitted to indicate a change of the icons database
    """

    changed = pyqtSignal()

    def __init__(self, parent=None):
        """
        Constructor

        @param parent reference to the parent object (QObject)
        """
        super().__init__(parent)

        self.__encoding = "iso-8859-1"
        self.__iconsFileName = "web_site_icons.json"
        self.__iconDatabasePath = ""  # saving of icons disabled

        self.__iconsDB = {}
        self.__loaded = False

        self.__saveTimer = AutoSaver(self, self.save)

        self.changed.connect(self.__saveTimer.changeOccurred)

    def setIconDatabasePath(self, path):
        """
        Public method to set the path for the web site icons store.

        @param path path to store the icons file to
        @type str
        """
        if path != self.__iconDatabasePath:
            self.close()

        self.__iconDatabasePath = path

    def iconDatabasePath(self):
        """
        Public method o get the path for the web site icons store.

        @return path to store the icons file to
        @rtype str
        """
        return self.__iconDatabasePath

    def close(self):
        """
        Public method to close the web icon provider.
        """
        self.__saveTimer.saveIfNeccessary()
        self.__loaded = False
        self.__iconsDB = {}

    def load(self):
        """
        Public method to load the web site icons.
        """
        if self.__loaded:
            return

        if self.__iconDatabasePath:
            filename = os.path.join(self.__iconDatabasePath, self.__iconsFileName)
            try:
                with open(filename, "r") as f:
                    db = json.load(f)
            except OSError:
                # ignore silentyl
                db = {}

            self.__iconsDB = {}
            for url, data in db.items():
                self.__iconsDB[url] = QIcon(
                    QPixmap.fromImage(
                        QImage.fromData(QByteArray(data.encode(self.__encoding)))
                    )
                )

        self.__loaded = True

    def save(self):
        """
        Public method to save the web site icons.
        """
        if not self.__loaded:
            return

        from WebBrowser.WebBrowserWindow import WebBrowserWindow

        if not WebBrowserWindow.isPrivate() and bool(self.__iconDatabasePath):
            db = {}
            for url, icon in self.__iconsDB.items():
                ba = QByteArray()
                buffer = QBuffer(ba)
                buffer.open(QIODevice.OpenModeFlag.WriteOnly)
                icon.pixmap(32).toImage().save(buffer, "PNG")
                db[url] = bytes(buffer.data()).decode(self.__encoding)

            filename = os.path.join(self.__iconDatabasePath, self.__iconsFileName)
            with contextlib.suppress(OSError), open(filename, "w") as f:
                json.dump(db, f)

    def saveIcon(self, view):
        """
        Public method to save a web site icon.

        @param view reference to the view object
        @type WebBrowserView
        """
        scheme = view.url().scheme()
        if scheme in ["eric", "about", "qthelp", "file", "abp", "ftp"]:
            return

        self.load()

        if view.mainWindow().isPrivate():
            return

        urlStr = self.__urlToString(view.url())
        self.__iconsDB[urlStr] = view.icon()

        self.changed.emit()

    def __urlToString(self, url):
        """
        Private method to convert an URL to a string.

        @param url URL to be converted
        @type QUrl
        @return string representation of the URL
        @rtype str
        """
        return url.toString(
            QUrl.UrlFormattingOption.RemoveUserInfo
            | QUrl.UrlFormattingOption.RemoveFragment
            | QUrl.UrlFormattingOption.RemovePath
        )

    def iconForUrl(self, url):
        """
        Public method to get an icon for an URL.

        @param url URL to get icon for
        @type QUrl
        @return icon for the URL
        @rtype QIcon
        """
        scheme2iconName = {
            "eric": "ericWeb",
            "about": "ericWeb",
            "qthelp": "qthelp",
            "file": "fileMisc",
            "abp": "adBlockPlus",
            "ftp": "network-server",
        }

        scheme = url.scheme()
        iconName = scheme2iconName.get(scheme)
        if iconName:
            return UI.PixmapCache.getIcon(iconName)

        self.load()

        urlStr = self.__urlToString(url)
        if urlStr in self.__iconsDB:
            return self.__iconsDB[urlStr]
        else:
            for iconUrlStr in self.__iconsDB:
                if iconUrlStr.startswith(urlStr):
                    return self.__iconsDB[iconUrlStr]

        # try replacing http scheme with https scheme
        url = QUrl(url)
        if url.scheme() == "http":
            url.setScheme("https")
            urlStr = self.__urlToString(url)
            if urlStr in self.__iconsDB:
                return self.__iconsDB[urlStr]
            else:
                for iconUrlStr in self.__iconsDB:
                    if iconUrlStr.startswith(urlStr):
                        return self.__iconsDB[iconUrlStr]

        if scheme == "https":
            return UI.PixmapCache.getIcon("securityHigh32")
        else:
            return UI.PixmapCache.getIcon("defaultIcon")

    def clear(self):
        """
        Public method to clear the icons cache.
        """
        self.load()
        self.__iconsDB = {}
        self.changed.emit()
        self.__saveTimer.saveIfNeccessary()

    def showWebIconDialog(self):
        """
        Public method to show a dialog to manage the Favicons.
        """
        self.load()

        from .WebIconDialog import WebIconDialog

        dlg = WebIconDialog(self.__iconsDB)
        if dlg.exec() == QDialog.DialogCode.Accepted:
            changed = False
            urls = dlg.getUrls()
            for url in list(self.__iconsDB.keys())[:]:
                if url not in urls:
                    del self.__iconsDB[url]
                    changed = True
            if changed:
                self.changed.emit()


_WebIconProvider = None


def instance():
    """
    Global function to get a reference to the web icon provider and create it,
    if it hasn't been yet.

    @return reference to the web icon provider object
    @rtype WebIconProvider
    """
    global _WebIconProvider

    if _WebIconProvider is None:
        _WebIconProvider = WebIconProvider()

    return _WebIconProvider

eric ide

mercurial