diff -r 4e8b98454baa -r 800c432b34c8 eric7/WebBrowser/Tools/WebIconProvider.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/WebBrowser/Tools/WebIconProvider.py Sat May 15 18:45:04 2021 +0200 @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2016 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module containing a web site icon storage object. +""" + +import json +import os +import contextlib + +from PyQt5.QtCore import ( + pyqtSignal, QObject, QByteArray, QBuffer, QIODevice, QUrl +) +from PyQt5.QtGui import QIcon, QPixmap, QImage +from PyQt5.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.ComponentFormattingOption.PrettyDecoded | + 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