Sat, 31 Dec 2022 16:23:21 +0100
Updated copyright for 2023.
# -*- coding: utf-8 -*- # Copyright (c) 2016 - 2023 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module containing a web site icon storage object. """ import contextlib import json import os from PyQt6.QtCore import QBuffer, QByteArray, QIODevice, QObject, QUrl, pyqtSignal from PyQt6.QtGui import QIcon, QImage, QPixmap from PyQt6.QtWidgets import QDialog from eric7.EricGui import EricPixmapCache from eric7.Utilities.AutoSaver import AutoSaver 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 eric7.WebBrowser.WebBrowserWindow import ( # __IGNORE_WARNING_I101__ 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 EricPixmapCache.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 EricPixmapCache.getIcon("securityHigh32") else: return EricPixmapCache.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, parent=None): """ Public method to show a dialog to manage the Favicons. @param parent reference to the parent widget @type QWidget """ from .WebIconDialog import WebIconDialog self.load() dlg = WebIconDialog(self.__iconsDB, parent=parent) 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