Sun, 07 Feb 2016 18:08:48 +0100
Continued porting the web browser.
- added a web icon loader
- added a web icon provider
- added the zoom manager
--- a/Preferences/__init__.py Sat Feb 06 17:43:59 2016 +0100 +++ b/Preferences/__init__.py Sun Feb 07 18:08:48 2016 +0100 @@ -1015,6 +1015,7 @@ "WarnOnMultipleClose": True, "DefaultScheme": "https://", "UserStyleSheet": "", + "ZoomValuesDB": "{}", # empty JSON dictionary } @classmethod
--- a/WebBrowser/JavaScript/AutoFillJsObject.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/JavaScript/AutoFillJsObject.py Sun Feb 07 18:08:48 2016 +0100 @@ -36,6 +36,15 @@ def formSubmitted(self, urlStr, userName, password, data): """ Public slot passing form data to the auto fill manager. + + @param urlStr form submission URL + @type str + @param userName name of the user + @type str + @param password user password + @type str + @param data data to be submitted + @type QByteArray """ # TODO: AutoFill pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Network/FollowRedirectReply.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a network reply delegate allowing to check redirects. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSignal, QObject +from PyQt5.QtNetwork import QNetworkRequest + + +class FollowRedirectReply(QObject): + """ + Class implementing a network reply delegate allowing to check redirects. + """ + finished = pyqtSignal() + + def __init__(self, url, manager, maxRedirects=5): + """ + Constructor + + @param url URL to get (QUrl) + @param manager reference to the network access manager + (QNetworkAccessManager) + @keyparam maxRedirects maximum allowed redirects (integer) + """ + super(FollowRedirectReply, self).__init__() + + self.__manager = manager + self.__maxRedirects = maxRedirects + self.__redirectCount = 0 + + self.__reply = self.__manager.get(QNetworkRequest(url)) + self.__reply.finished.connect(self.__replyFinished) + + def reply(self): + """ + Public method to get the reply object. + + @return reference to the reply object (QNetworkReply) + """ + return self.__reply + + def originalUrl(self): + """ + Public method to get the original URL. + + @return original URL (QUrl) + """ + return self.__reply.request().url() + + def url(self): + """ + Public method to get the final URL (after redirects). + + @return final URL (QUrl) + """ + return self.__reply.url() + + def error(self): + """ + Public method to get the error information. + + @return error code (QNetworkReply.NetworkError) + """ + return self.__reply.error() + + def errorString(self): + """ + Public method to get the error message. + + @return error message (string) + """ + return self.__reply.errorString() + + def readAll(self): + """ + Public method to read all received data. + + @return received raw data (QByteArray) + """ + return self.__reply.readAll() + + def close(self): + """ + Public method to close the data stream. + """ + self.__reply.close() + + def __replyFinished(self): + """ + Private slot handling the receipt of the requested data. + """ + replyStatus = self.__reply.attribute( + QNetworkRequest.HttpStatusCodeAttribute) + if (replyStatus != 301 and replyStatus != 302) or \ + self.__redirectCount == self.__maxRedirects: + self.finished.emit() + return + + self.__redirectCount += 1 + + redirectUrl = self.__reply.attribute( + QNetworkRequest.RedirectionTargetAttribute) + self.__reply.close() + self.__reply.deleteLater() + self.__reply = None + + self.__reply = self.__manager.get(QNetworkRequest(redirectUrl)) + self.__reply.finished.connect(self.__replyFinished)
--- a/WebBrowser/Network/NetworkManager.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/Network/NetworkManager.py Sun Feb 07 18:08:48 2016 +0100 @@ -7,6 +7,8 @@ Module implementing a network manager class. """ +from __future__ import unicode_literals + from PyQt5.QtNetwork import QNetworkAccessManager from E5Gui import E5MessageBox @@ -34,7 +36,7 @@ def certificateError(self, error, view): """ - Protected method to handle SSL certificate errors. + Public method to handle SSL certificate errors. @param error object containing the certificate error information @type QWebEngineCertificateError
--- a/WebBrowser/Tools/Scripts.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/Tools/Scripts.py Sun Feb 07 18:08:48 2016 +0100 @@ -56,6 +56,8 @@ """ Function generating a script to set a user style sheet. + @param css style sheet to be applied + @type str @return script to set a user style sheet @rtype str """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Tools/WebIconLoader.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an object to load web site icons. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject +from PyQt5.QtGui import QIcon, QPixmap, QImage + +from ..Network.FollowRedirectReply import FollowRedirectReply + +import WebBrowser.WebBrowserWindow + + +class WebIconLoader(QObject): + """ + Class implementing a loader for web site icons. + + @signal iconLoaded(icon) emitted when the con has been loaded + """ + iconLoaded = pyqtSignal(QIcon) + + def __init__(self, url, parent=None): + """ + Constructor + + @param url URL to fetch the icon from + @type QUrl + @param parent reference to the parent object + @type QObject + """ + super(WebIconLoader, self).__init__(parent) + + networkManager = \ + WebBrowser.WebBrowserWindow.WebBrowserWindow.networkManager() + self.__reply = FollowRedirectReply(url, networkManager) + self.__reply.finished.connect(self.__finished) + + @pyqtSlot() + def __finished(self): + """ + Private slot handling the downloaded icon. + """ + # ignore any errors and emit an empty icon in this case + data = self.__reply.readAll() + icon = QIcon(QPixmap.fromImage(QImage.fromData(data))) + self.iconLoaded.emit(icon) + + self.__reply.deleteLater() + self.__reply = None
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Tools/WebIconProvider.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module containing a web site icon storage object. +""" + +from __future__ import unicode_literals + +import json +import os + +from PyQt5.QtCore import pyqtSignal, QObject, QByteArray, QBuffer, QIODevice, \ + QUrl +from PyQt5.QtGui import QIcon, QPixmap, QImage + +from Utilities.AutoSaver import AutoSaver + +import UI.PixmapCache + + +class WebIconProvider(QObject): + """ + Class implementing a web site icon storage. + """ + changed = pyqtSignal() + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QObject) + """ + super(WebIconProvider, self).__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 bookmarks. + """ + if self.__loaded: + return + + if self.__iconDatabasePath: + filename = os.path.join(self.__iconDatabasePath, + self.__iconsFileName) + try: + f = open(filename, "r") + db = json.load(f) + f.close() + except (IOError, 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 zoom values. + """ + if not self.__loaded: + return + + if self.__iconDatabasePath: + db = {} + for url, icon in self.__iconsDB.items(): + ba = QByteArray() + buffer = QBuffer(ba) + buffer.open(QIODevice.WriteOnly) + icon.pixmap(32).toImage().save(buffer, "PNG") + db[url] = bytes(buffer.data()).decode(self.__encoding) + + filename = os.path.join(self.__iconDatabasePath, + self.__iconsFileName) + try: + f = open(filename, "w") + json.dump(db, f) + f.close() + except (IOError, OSError): + # ignore silentyl + pass + + 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.PrettyDecoded | QUrl.RemoveUserInfo | + QUrl.RemoveFragment) + + 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 + """ + scheme = url.scheme() + if scheme in ["eric", "about"]: + return UI.PixmapCache.getIcon("ericWeb.png") + elif scheme == "qthelp": + return UI.PixmapCache.getIcon("qthelp.png") + elif scheme == "file": + return UI.PixmapCache.getIcon("fileMisc.png") + elif scheme == "abp": + return UI.PixmapCache.getIcon("adBlockPlus.png") + elif scheme == "ftp": + return UI.PixmapCache.getIcon("network-server.png") + + self.load() + + urlStr = self.__urlToString(url) + if url in self.__iconsDB: + return self.__iconsDB[urlStr] + else: + return UI.PixmapCache.getIcon("defaultIcon.png") + + +__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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/UrlBar/FavIconLabel.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2010 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the label to show the web site icon. +""" + +from __future__ import unicode_literals +try: + str = unicode +except NameError: + pass + +from PyQt5.QtCore import Qt, QPoint, QMimeData +from PyQt5.QtGui import QDrag, QPixmap +from PyQt5.QtWidgets import QLabel, QApplication + + +class FavIconLabel(QLabel): + """ + Class implementing the label to show the web site icon. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + """ + super(FavIconLabel, self).__init__(parent) + + self.__browser = None + self.__dragStartPos = QPoint() + + self.setFocusPolicy(Qt.NoFocus) + self.setCursor(Qt.ArrowCursor) + self.setMinimumSize(16, 16) + self.resize(16, 16) + + self.__browserIconChanged() + + def __browserIconChanged(self): + """ + Private slot to set the icon. + """ + if self.__browser: + self.setPixmap( + self.__browser.icon().pixmap(16, 16)) + + def __clearIcon(self): + """ + Private slot to clear the icon. + """ + self.setPixmap(QPixmap()) + + def setBrowser(self, browser): + """ + Public method to set the browser connection. + + @param browser reference to the browser widegt (HelpBrowser) + """ + self.__browser = browser + self.__browser.loadFinished.connect(self.__browserIconChanged) + self.__browser.iconChanged.connect(self.__browserIconChanged) + self.__browser.loadStarted.connect(self.__clearIcon) + + def mousePressEvent(self, evt): + """ + Protected method to handle mouse press events. + + @param evt reference to the mouse event (QMouseEvent) + """ + if evt.button() == Qt.LeftButton: + self.__dragStartPos = evt.pos() + super(FavIconLabel, self).mousePressEvent(evt) + + def mouseMoveEvent(self, evt): + """ + Protected method to handle mouse move events. + + @param evt reference to the mouse event (QMouseEvent) + """ + if evt.button() == Qt.LeftButton and \ + (evt.pos() - self.__dragStartPos).manhattanLength() > \ + QApplication.startDragDistance() and \ + self.__browser is not None: + drag = QDrag(self) + mimeData = QMimeData() + title = self.__browser.title() + if title == "": + title = str(self.__browser.url().toEncoded(), encoding="utf-8") + mimeData.setText(title) + mimeData.setUrls([self.__browser.url()]) + p = self.pixmap() + if p: + drag.setPixmap(p) + drag.setMimeData(mimeData) + drag.exec_()
--- a/WebBrowser/UrlBar/UrlBar.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/UrlBar/UrlBar.py Sun Feb 07 18:08:48 2016 +0100 @@ -27,7 +27,7 @@ import WebBrowser.WebBrowserWindow -##from .FavIconLabel import FavIconLabel +from .FavIconLabel import FavIconLabel ##from .SslLabel import SslLabel ## import UI.PixmapCache @@ -60,9 +60,8 @@ ## self.__bmInactiveIcon = QIcon( ## self.__bmActiveIcon.pixmap(16, 16, QIcon.Disabled)) - # TODO: FavIcon -## self.__favicon = FavIconLabel(self) -## self.addWidget(self.__favicon, E5LineEdit.LeftSide) + self.__favicon = FavIconLabel(self) + self.addWidget(self.__favicon, E5LineEdit.LeftSide) # TODO: SSL ## self.__sslLabel = SslLabel(self) @@ -120,8 +119,7 @@ @param browser reference to the browser widget (WebBrowserView) """ self.__browser = browser - # TODO: FavIcon -## self.__favicon.setBrowser(browser) + self.__favicon.setBrowser(browser) self.__browser.urlChanged.connect(self.__browserUrlChanged) self.__browser.loadProgress.connect(self.update)
--- a/WebBrowser/WebBrowserPage.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/WebBrowserPage.py Sun Feb 07 18:08:48 2016 +0100 @@ -201,7 +201,7 @@ def acceptNavigationRequest(self, url, type_, isMainFrame): """ - Protected method to determine, if a request may be accepted. + Public method to determine, if a request may be accepted. @param url URL to navigate to @type QUrl @@ -490,7 +490,7 @@ ## .userAgentForUrl(url) ## if agent == "": ## # no agent string specified for the given host -> use global one -## agent = Preferences.getHelp("UserAgent") +## agent = Preferences.getWebBrowser("UserAgent") ## if agent == "": ## # no global agent string specified -> use default one ## agent = QWebPage.userAgentForUrl(self, url) @@ -774,7 +774,7 @@ def certificateError(self, error): """ - Protected method to handle SSL certificate errors. + Public method to handle SSL certificate errors. @param error object containing the certificate error information @type QWebEngineCertificateError
--- a/WebBrowser/WebBrowserTabBar.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/WebBrowserTabBar.py Sun Feb 07 18:08:48 2016 +0100 @@ -86,7 +86,7 @@ super(WebBrowserTabBar, self).mouseMoveEvent(evt) # TODO: page preview -## if Preferences.getHelp("ShowPreview"): +## if Preferences.getWebBrowser("ShowPreview"): ## # Find the tab under the mouse ## i = 0 ## tabIndex = -1 @@ -117,7 +117,7 @@ @param evt reference to the leave event (QEvent) """ # TODO: page preview -## if Preferences.getHelp("ShowPreview"): +## if Preferences.getWebBrowser("ShowPreview"): ## # If leave tabwidget then hide previous tab preview ## if self.__previewPopup is not None: ## self.__previewPopup.hide() @@ -132,7 +132,7 @@ @param evt reference to the mouse press event (QMouseEvent) """ # TODO: page preview -## if Preferences.getHelp("ShowPreview"): +## if Preferences.getWebBrowser("ShowPreview"): ## if self.__previewPopup is not None: ## self.__previewPopup.hide() ## self.__currentTabPreviewIndex = -1 @@ -151,7 +151,7 @@ """ # TODO: page preview ## if evt.type() == QEvent.ToolTip and \ -## Preferences.getHelp("ShowPreview"): +## Preferences.getWebBrowser("ShowPreview"): ## # suppress tool tips if we are showing previews ## evt.setAccepted(True) ## return True @@ -166,7 +166,7 @@ """ pass # TODO: page preview -## if Preferences.getHelp("ShowPreview"): +## if Preferences.getWebBrowser("ShowPreview"): ## if self.__previewPopup is not None: ## self.__previewPopup.hide() ## self.__currentTabPreviewIndex = -1
--- a/WebBrowser/WebBrowserTabWidget.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/WebBrowserTabWidget.py Sun Feb 07 18:08:48 2016 +0100 @@ -348,7 +348,7 @@ browser.forwardAvailable.connect(self.__mainWindow.setForwardAvailable) browser.loadStarted.connect(self.__loadStarted) browser.loadFinished.connect(self.__loadFinished) - browser.iconUrlChanged.connect(self.__iconUrlChanged) + browser.iconChanged.connect(self.__iconChanged) browser.search.connect(self.newBrowser) browser.page().windowCloseRequested.connect( self.__windowCloseRequested) @@ -796,21 +796,18 @@ self.__mainWindow.setLoadingActions(False) - def __iconUrlChanged(self, url): + def __iconChanged(self): """ - Private slot to handle a change of the icon URL. - - @param url URL of the icon - @type QUrl + Private slot to handle a change of the web site icon. """ browser = self.sender() if browser is not None and isinstance(browser, QWidget): - import WebBrowser.WebBrowserWindow self.setTabIcon( self.indexOf(browser), - WebBrowser.WebBrowserWindow.WebBrowserWindow.icon(url)) + browser.icon()) # TODO: Bookmarks +## import WebBrowser.WebBrowserWindow ## WebBrowser.WebBrowserWindow.WebBrowserWindow.bookmarksManager()\ ## .iconChanged(url)
--- a/WebBrowser/WebBrowserView.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/WebBrowserView.py Sun Feb 07 18:08:48 2016 +0100 @@ -18,7 +18,7 @@ QUrl, QBuffer, QIODevice, QFileInfo, Qt, QTimer, QEvent, \ QRect, QFile, QPoint, QByteArray, qVersion from PyQt5.QtGui import QDesktopServices, QClipboard, QMouseEvent, QColor, \ - QPalette + QPalette, QIcon from PyQt5.QtWidgets import qApp, QStyle, QMenu, QApplication, QInputDialog, \ QLineEdit, QLabel, QToolTip, QFrame, QDialog from PyQt5.QtPrintSupport import QPrinter, QPrintDialog @@ -30,6 +30,8 @@ import WebBrowser from .WebBrowserPage import WebBrowserPage +from .Tools.WebIconLoader import WebIconLoader + import Preferences import UI.PixmapCache import Globals @@ -51,6 +53,7 @@ @signal highlighted(str) emitted, when the mouse hovers over a link @signal search(QUrl) emitted, when a search is requested @signal zoomValueChanged(int) emitted to signal a change of the zoom value + @signal iconChanged() emitted to signal a changed web site icon """ sourceChanged = pyqtSignal(QUrl) forwardAvailable = pyqtSignal(bool) @@ -58,6 +61,7 @@ highlighted = pyqtSignal(str) search = pyqtSignal(QUrl) zoomValueChanged = pyqtSignal(int) + iconChanged = pyqtSignal() ZoomLevels = [ 30, 40, 50, 67, 80, 90, @@ -90,6 +94,8 @@ self.__ctrlPressed = False self.__isLoading = False self.__progress = 0 + self.__siteIconLoader = None + self.__siteIcon = QIcon() self.__currentZoom = 100 self.__zoomLevels = WebBrowserView.ZoomLevels[:] @@ -102,6 +108,7 @@ ## self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) ## self.linkClicked.connect(self.setSource) ## + self.iconUrlChanged.connect(self.__iconUrlChanged) self.urlChanged.connect(self.__urlChanged) ## self.statusBarMessage.connect(self.__statusBarMessage) self.page().linkHovered.connect(self.__linkHovered) @@ -125,7 +132,7 @@ self.setAcceptDrops(True) # TODO: Access Keys -## self.__enableAccessKeys = Preferences.getHelp("AccessKeysEnabled") +## self.__enableAccessKeys = Preferences.getWebBrowser("AccessKeysEnabled") ## self.__accessKeysPressed = False ## self.__accessKeyLabels = [] ## self.__accessKeyNodes = {} @@ -223,6 +230,15 @@ ## if self.url().toString() == "eric:home": ## self.reload() + def mainWindow(self): + """ + Public method to get a reference to the main window. + + @return reference to the main window + @rtype WebBrowserWindow + """ + return self.__mw + # TODO: eliminate requestData, add param to get rid of __ctrlPressed def setSource(self, name, requestData=None): """ @@ -415,13 +431,12 @@ zoom manager @type bool """ - if value != self.zoomValue(): + if value != self.__currentZoom: self.setZoomFactor(value / 100.0) self.__currentZoom = value - # TODO: Zoom Manager -## if saveValue: -## Helpviewer.HelpWindow.HelpWindow.zoomManager().setZoomValue( -## self.url(), value) + if saveValue and not self.__mw.isPrivate(): + from .ZoomManager import ZoomManager + ZoomManager.instance().setZoomValue(self.url(), value) self.zoomValueChanged.emit(value) def zoomValue(self): @@ -481,7 +496,6 @@ @param callback reference to a function with a bool parameter @type function(bool) or None """ - findFlags = QWebEnginePage.FindFlags() if case: findFlags |= QWebEnginePage.FindCaseSensitively @@ -547,8 +561,8 @@ ## UI.PixmapCache.getIcon("mailSend.png"), ## self.tr("Send Link"), ## self.__sendLink).setData(hit.linkUrl()) -## if Preferences.getHelp("VirusTotalEnabled") and \ -## Preferences.getHelp("VirusTotalServiceKey") != "": +## if Preferences.getWebBrowser("VirusTotalEnabled") and \ +## Preferences.getWebBrowser("VirusTotalServiceKey") != "": ## menu.addAction( ## UI.PixmapCache.getIcon("virustotal.png"), ## self.tr("Scan Link with VirusTotal"), @@ -580,8 +594,8 @@ ## UI.PixmapCache.getIcon("adBlockPlus.png"), ## self.tr("Block Image"), self.__blockImage)\ ## .setData(hit.imageUrl().toString()) -## if Preferences.getHelp("VirusTotalEnabled") and \ -## Preferences.getHelp("VirusTotalServiceKey") != "": +## if Preferences.getWebBrowser("VirusTotalEnabled") and \ +## Preferences.getWebBrowser("VirusTotalServiceKey") != "": ## menu.addAction( ## UI.PixmapCache.getIcon("virustotal.png"), ## self.tr("Scan Image with VirusTotal"), @@ -1305,7 +1319,7 @@ def eventFilter(self, obj, evt): """ - Protected method to process event for other objects. + Public method to process event for other objects. @param obj reference to object to process events for @type QObject @@ -1377,6 +1391,46 @@ self.forwardAvailable.emit(self.isForwardAvailable()) self.backwardAvailable.emit(self.isBackwardAvailable()) + def __iconUrlChanged(self, url): + """ + Private slot to handle the iconUrlChanged signal. + + @param url URL to get web site icon from + @type QUrl + """ + self.__siteIcon = QIcon() + if self.__siteIconLoader is not None: + self.__siteIconLoader.deleteLater() + self.__siteIconLoader = WebIconLoader(url, self) + self.__siteIconLoader.iconLoaded.connect(self.__iconLoaded) + + def __iconLoaded(self, icon): + """ + Private slot handling the loaded web site icon. + + @param icon web site icon + @type QIcon + """ + self.__siteIcon = icon + + from .Tools import WebIconProvider + WebIconProvider.instance().saveIcon(self) + + self.iconChanged.emit() + + def icon(self): + """ + Public method to get the web site icon. + + @return web site icon + @rtype QIcon + """ + if not self.__siteIcon.isNull(): + return QIcon(self.__siteIcon) + + from .Tools import WebIconProvider + return WebIconProvider.instance().iconForUrl(self.url()) + ## def __statusBarMessage(self, text): ## """ ## Private slot to handle the statusBarMessage signal. @@ -1422,15 +1476,14 @@ self.__progress = 0 # TODO: ClickToFlash (?) -## if Preferences.getHelp("ClickToFlashEnabled"): +## if Preferences.getWebBrowser("ClickToFlashEnabled"): ## # this is a hack to make the ClickToFlash button appear ## self.zoomIn() ## self.zoomOut() - # TODO: Zoom Manager -## zoomValue = Helpviewer.HelpWindow.HelpWindow.zoomManager()\ -## .zoomValue(self.url()) -## self.setZoomValue(zoomValue) + from .ZoomManager import ZoomManager + zoomValue = ZoomManager.instance().zoomValue(self.url()) + self.setZoomValue(zoomValue) if ok: pass @@ -1794,7 +1847,7 @@ Public method to indicate a change of the settings. """ # TODO: Access Keys -## self.__enableAccessKeys = Preferences.getHelp("AccessKeysEnabled") +## self.__enableAccessKeys = Preferences.getWebBrowser("AccessKeysEnabled") ## if not self.__enableAccessKeys: ## self.__hideAccessKeys()
--- a/WebBrowser/WebBrowserWindow.py Sat Feb 06 17:43:59 2016 +0100 +++ b/WebBrowser/WebBrowserWindow.py Sun Feb 07 18:08:48 2016 +0100 @@ -56,7 +56,9 @@ ##from .data import javascript_rc # __IGNORE_WARNING__ ## -from .Tools import Scripts, WebBrowserTools +from .Tools import Scripts, WebBrowserTools, WebIconProvider + +from .ZoomManager import ZoomManager class WebBrowserWindow(E5MainWindow): @@ -95,7 +97,6 @@ _notification = None ## _featurePermissionManager = None ## _flashCookieManager = None -## _zoomManager = None def __init__(self, home, path, parent, name, fromEric=False, initShortcutsOnly=False, searchWord=None, @@ -178,7 +179,7 @@ ## if WebBrowserWindow.UseQtHelp: ## self.__helpEngine = \ ## QHelpEngine(os.path.join(Utilities.getConfigDir(), -## "browser", "eric6help.qhc"), self) +## "web_browser", "eric6help.qhc"), self) ## self.__removeOldDocumentation() ## self.__helpEngine.warning.connect(self.__warning) ## else: @@ -256,7 +257,7 @@ else: self.restoreGeometry(g) -## self.__setIconDatabasePath() + self.__setIconDatabasePath() self.__initWebEngineSettings() self.__initActions() @@ -277,7 +278,7 @@ ## self.__adBlockIcon = AdBlockIcon(self) ## self.statusBar().addPermanentWidget(self.__adBlockIcon) ## self.__adBlockIcon.setEnabled( -## Preferences.getHelp("AdBlockEnabled")) +## Preferences.getWebBrowser("AdBlockEnabled")) ## self.__tabWidget.currentChanged[int].connect( ## self.__adBlockIcon.currentChanged) ## self.__tabWidget.sourceChanged.connect( @@ -353,24 +354,28 @@ """ Public method to check, if the web browser was called from within the eric IDE. + + @return flag indicating that the browserw as opened from within eric + @rtype bool """ return self.__fromEric -## def __setIconDatabasePath(self, enable=True): -## """ -## Private method to set the favicons path. -## -## @param enable flag indicating to enabled icon storage (boolean) -## """ -## if enable: -## iconDatabasePath = os.path.join(Utilities.getConfigDir(), -## "browser", "favicons") -## if not os.path.exists(iconDatabasePath): -## os.makedirs(iconDatabasePath) -## else: -## iconDatabasePath = "" # setting an empty path disables it -## QWebSettings.setIconDatabasePath(iconDatabasePath) -## + def __setIconDatabasePath(self, enable=True): + """ + Private method to set the favicons path. + + @param enable flag indicating to enabled icon storage (boolean) + """ + if enable: + iconDatabasePath = os.path.join(Utilities.getConfigDir(), + "web_browser", "favicons") + if not os.path.exists(iconDatabasePath): + os.makedirs(iconDatabasePath) + else: + iconDatabasePath = "" # setting an empty path disables it + + WebIconProvider.instance().setIconDatabasePath(iconDatabasePath) + def __initWebEngineSettings(self): """ Private method to set the global web settings. @@ -396,7 +401,7 @@ QWebEngineSettings.MinimumLogicalFontSize, Preferences.getWebBrowser("MinimumLogicalFontSize")) - styleSheet = Preferences.getHelp("UserStyleSheet") + styleSheet = Preferences.getWebBrowser("UserStyleSheet") self.__setUserStyleSheet(styleSheet) settings.setAttribute( @@ -404,7 +409,7 @@ Preferences.getWebBrowser("AutoLoadImages")) ## settings.setAttribute( ## QWebSettings.JavaEnabled, -## Preferences.getHelp("JavaEnabled")) +## Preferences.getWebBrowser("JavaEnabled")) settings.setAttribute( QWebEngineSettings.JavascriptEnabled, Preferences.getWebBrowser("JavaScriptEnabled")) @@ -416,37 +421,37 @@ Preferences.getWebBrowser("JavaScriptCanAccessClipboard")) ## settings.setAttribute( ## QWebSettings.PluginsEnabled, -## Preferences.getHelp("PluginsEnabled")) +## Preferences.getWebBrowser("PluginsEnabled")) ## if hasattr(QWebSettings, "PrintElementBackgrounds"): ## settings.setAttribute( ## QWebSettings.PrintElementBackgrounds, -## Preferences.getHelp("PrintBackgrounds")) +## Preferences.getWebBrowser("PrintBackgrounds")) ## ## if hasattr(QWebSettings, "setOfflineStoragePath"): ## settings.setAttribute( ## QWebSettings.OfflineStorageDatabaseEnabled, -## Preferences.getHelp("OfflineStorageDatabaseEnabled")) +## Preferences.getWebBrowser("OfflineStorageDatabaseEnabled")) ## webDatabaseDir = os.path.join( -## Utilities.getConfigDir(), "browser", "webdatabases") +## Utilities.getConfigDir(), "web_browser", "webdatabases") ## if not os.path.exists(webDatabaseDir): ## os.makedirs(webDatabaseDir) ## settings.setOfflineStoragePath(webDatabaseDir) ## settings.setOfflineStorageDefaultQuota( -## Preferences.getHelp("OfflineStorageDatabaseQuota") * +## Preferences.getWebBrowser("OfflineStorageDatabaseQuota") * ## 1024 * 1024) ## ## if hasattr(QWebSettings, "OfflineWebApplicationCacheEnabled"): ## settings.setAttribute( ## QWebSettings.OfflineWebApplicationCacheEnabled, -## Preferences.getHelp("OfflineWebApplicationCacheEnabled")) +## Preferences.getWebBrowser("OfflineWebApplicationCacheEnabled")) ## appCacheDir = os.path.join( -## Utilities.getConfigDir(), "browser", "webappcaches") +## Utilities.getConfigDir(), "web_browser", "webappcaches") ## if not os.path.exists(appCacheDir): ## os.makedirs(appCacheDir) ## settings.setOfflineWebApplicationCachePath(appCacheDir) ## settings.setOfflineWebApplicationCacheQuota( -## Preferences.getHelp("OfflineWebApplicationCacheQuota") * +## Preferences.getWebBrowser("OfflineWebApplicationCacheQuota") * ## 1024 * 1024) ## if self.isPrivate(): @@ -457,7 +462,7 @@ QWebEngineSettings.LocalStorageEnabled, Preferences.getWebBrowser("LocalStorageEnabled")) ## localStorageDir = os.path.join( -## Utilities.getConfigDir(), "browser", "weblocalstorage") +## Utilities.getConfigDir(), "web_browser", "weblocalstorage") ## if not os.path.exists(localStorageDir): ## os.makedirs(localStorageDir) ## settings.setLocalStoragePath(localStorageDir) @@ -465,7 +470,7 @@ ## if hasattr(QWebSettings, "DnsPrefetchEnabled"): ## settings.setAttribute( ## QWebSettings.DnsPrefetchEnabled, -## Preferences.getHelp("DnsPrefetchEnabled")) +## Preferences.getWebBrowser("DnsPrefetchEnabled")) ## settings.setDefaultTextEncoding( Preferences.getWebBrowser("DefaultTextEncoding")) @@ -488,7 +493,7 @@ ## if hasattr(QWebSettings, "SiteSpecificQuirksEnabled"): ## settings.setAttribute( ## QWebSettings.SiteSpecificQuirksEnabled, -## Preferences.getHelp("SiteSpecificQuirksEnabled")) +## Preferences.getWebBrowser("SiteSpecificQuirksEnabled")) ## ## QWebSecurityOrigin.addLocalScheme("eric") settings.setAttribute( @@ -1639,27 +1644,27 @@ ## self.__showSyncDialog) ## self.__actions.append(self.synchronizationAct) - # TODO: Zoom Manager -## self.zoomValuesAct = E5Action( -## self.tr('Manage Saved Zoom Values'), -## UI.PixmapCache.getIcon("zoomReset.png"), -## self.tr('Manage Saved Zoom Values...'), -## 0, 0, -## self, 'webbrowser_manage_zoom_values') -## self.zoomValuesAct.setStatusTip(self.tr( -## 'Manage the saved zoom values')) -## self.zoomValuesAct.setWhatsThis(self.tr( -## """<b>Manage Saved Zoom Values...</b>""" -## """<p>Opens a dialog to manage the saved zoom values.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.zoomValuesAct.triggered.connect(self.__showZoomValuesDialog) -## self.__actions.append(self.zoomValuesAct) + self.zoomValuesAct = E5Action( + self.tr('Manage Saved Zoom Values'), + UI.PixmapCache.getIcon("zoomReset.png"), + self.tr('Manage Saved Zoom Values...'), + 0, 0, + self, 'webbrowser_manage_zoom_values') + self.zoomValuesAct.setStatusTip(self.tr( + 'Manage the saved zoom values')) + self.zoomValuesAct.setWhatsThis(self.tr( + """<b>Manage Saved Zoom Values...</b>""" + """<p>Opens a dialog to manage the saved zoom values.</p>""" + )) + if not self.__initShortcutsOnly: + self.zoomValuesAct.triggered.connect(self.__showZoomValuesDialog) + self.__actions.append(self.zoomValuesAct) self.backAct.setEnabled(False) self.forwardAct.setEnabled(False) # now read the keyboard shortcuts for the actions + # TODO: change this to webBrowser Shortcuts.readShortcuts(helpViewer=self) def getActions(self): @@ -1782,8 +1787,8 @@ ## if SSL_AVAILABLE: ## menu.addAction(self.certificatesAct) ## menu.addSeparator() -## menu.addAction(self.zoomValuesAct) -## menu.addSeparator() + menu.addAction(self.zoomValuesAct) + menu.addSeparator() ## menu.addAction(self.adblockAct) ## menu.addAction(self.flashblockAct) ## menu.addSeparator() @@ -1991,8 +1996,8 @@ ## UI.PixmapCache.getIcon("virustotal.png"), ## self.tr("Domain Report"), ## self.__virusTotalDomainReport) -## if not Preferences.getHelp("VirusTotalEnabled") or \ -## Preferences.getHelp("VirusTotalServiceKey") == "": +## if not Preferences.getWebBrowser("VirusTotalEnabled") or \ +## Preferences.getWebBrowser("VirusTotalServiceKey") == "": ## self.virustotalScanCurrentAct.setEnabled(False) ## self.virustotalIpReportAct.setEnabled(False) ## self.virustotalDomainReportAct.setEnabled(False) @@ -2356,6 +2361,10 @@ ## self.speedDial().close() ## ## self.syncManager().close() + + ZoomManager.instance().close() + + WebIconProvider.instance().close() ## ## self.__virusTotal.close() ## @@ -2375,7 +2384,7 @@ self.__tabWidget.closeAllBrowsers() state = self.saveState() - Preferences.setWebBrowser("HelpViewerState", state) + Preferences.setWebBrowser("WebBrowserState", state) if Preferences.getWebBrowser("SaveGeometry"): if not self.__isFullScreen(): @@ -2631,8 +2640,8 @@ ## self.searchEdit.preferencesChanged() ## ## self.__virusTotal.preferencesChanged() -## if not Preferences.getHelp("VirusTotalEnabled") or \ -## Preferences.getHelp("VirusTotalServiceKey") == "": +## if not Preferences.getWebBrowser("VirusTotalEnabled") or \ +## Preferences.getWebBrowser("VirusTotalServiceKey") == "": ## self.virustotalScanCurrentAct.setEnabled(False) ## self.virustotalIpReportAct.setEnabled(False) ## self.virustotalDomainReportAct.setEnabled(False) @@ -2713,7 +2722,7 @@ ## if cls._helpEngine is None: ## cls._helpEngine = \ ## QHelpEngine(os.path.join(Utilities.getConfigDir(), -## "browser", "eric6help.qhc")) +## "web_browser", "eric6help.qhc")) ## return cls._helpEngine ## else: ## return None @@ -3156,7 +3165,7 @@ ## "{0}/flashplayer/help/settings_manager07.html".format( ## langCode)) ## if zoomValues: -## self.zoomManager().clear() +## ZoomManager.instance().clear() ## ## def __showEnginesConfigurationDialog(self): ## """ @@ -3225,15 +3234,15 @@ ## """ ## self.featurePermissionManager().showFeaturePermissionsDialog() ## -## def __showZoomValuesDialog(self): -## """ -## Private slot to show the zoom values management dialog. -## """ -## from .ZoomManager.ZoomValuesDialog import ZoomValuesDialog -## -## dlg = ZoomValuesDialog(self) -## dlg.exec_() -## + def __showZoomValuesDialog(self): + """ + Private slot to show the zoom values management dialog. + """ + from .ZoomManager.ZoomValuesDialog import ZoomValuesDialog + + dlg = ZoomValuesDialog(self) + dlg.exec_() + ## def __showNetworkMonitor(self): ## """ ## Private slot to show the network monitor dialog. @@ -3481,20 +3490,6 @@ ## ## return cls._flashCookieManager ## -## @classmethod -## def zoomManager(cls): -## """ -## Class method to get a reference to the zoom values manager. -## -## @return reference to the zoom values manager -## @rtype ZoomManager -## """ -## if cls._zoomManager is None: -## from .ZoomManager.ZoomManager import ZoomManager -## cls._zoomManager = ZoomManager() -## -## return cls._zoomManager -## @classmethod def mainWindow(cls): """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/ZoomManager/ZoomManager.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a manager for site specific zoom level settings. +""" + +from __future__ import unicode_literals + +import json + +from PyQt5.QtCore import pyqtSignal, QObject + +from Utilities.AutoSaver import AutoSaver +import Preferences + + +class ZoomManager(QObject): + """ + Class implementing a manager for site specific zoom level settings. + """ + changed = pyqtSignal() + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QObject) + """ + super(ZoomManager, self).__init__(parent) + + self.__zoomDB = {} + + self.__saveTimer = AutoSaver(self, self.save) + + self.changed.connect(self.__saveTimer.changeOccurred) + + self.__loaded = False + + def close(self): + """ + Public method to close the zoom manager. + """ + self.__saveTimer.saveIfNeccessary() + + def load(self): + """ + Public method to load the bookmarks. + """ + if self.__loaded: + return + + dbString = Preferences.getWebBrowser("ZoomValuesDB") + if dbString: + try: + db = json.loads(dbString) + self.__zoomDB = db + except ValueError: + # ignore silently + pass + + self.__loaded = True + + def save(self): + """ + Public method to save the zoom values. + """ + if not self.__loaded: + return + + dbString = json.dumps(self.__zoomDB) + Preferences.setWebBrowser("ZoomValuesDB", dbString) + + def __keyFromUrl(self, url): + """ + Private method to generate a DB key for an URL. + + @param url URL to generate a key for + @type QUrl + @return key for the given URL + @rtype str + """ + if url.isEmpty(): + key = "" + else: + scheme = url.scheme() + host = url.host() + if host: + key = host + elif scheme == "file": + path = url.path() + key = path.rsplit("/", 1)[0] + else: + key = "" + + return key + + def setZoomValue(self, url, zoomValue): + """ + Public method to record the zoom value for the given URL. + + Note: Only zoom values not equal 100% are recorded. + + @param url URL of the page to remember the zoom value for + @type QUrl + @param zoomValue zoom value for the URL + @type int + """ + self.load() + + key = self.__keyFromUrl(url) + if not key: + return + + if ((zoomValue == 100 and key not in self.__zoomDB) or + (key in self.__zoomDB and self.__zoomDB[key] == zoomValue)): + return + + if zoomValue == 100: + del self.__zoomDB[key] + else: + self.__zoomDB[key] = zoomValue + + self.changed.emit() + + def zoomValue(self, url): + """ + Public method to get the zoom value for an URL. + + @param url URL of the page to get the zoom value for + @type QUrl + @return zoomValue zoom value for the URL + @rtype int + """ + self.load() + + key = self.__keyFromUrl(url) + if not key: + zoom = 100 + + if key in self.__zoomDB: + zoom = self.__zoomDB[key] + else: + # default zoom value (i.e. no zoom) + zoom = 100 + + return zoom + + def clear(self): + """ + Public method to clear the saved zoom values. + """ + self.__zoomDB = {} + self.__loaded = True + + self.changed.emit() + + def removeZoomValue(self, site): + """ + Public method to remove a zoom value entry. + + @param site web site name + @type str + """ + self.load() + + if site in self.__zoomDB: + del self.__zoomDB[site] + self.changed.emit() + + def allSiteNames(self): + """ + Public method to get a list of all site names. + + @return sorted list of all site names + @rtype list of str + """ + self.load() + + return sorted(self.__zoomDB.keys()) + + def sitesCount(self): + """ + Public method to get the number of available sites. + + @return number of sites + @rtype int + """ + self.load() + + return len(self.__zoomDB) + + def siteInfo(self, site): + """ + Public method to get the zoom value for the site. + + @param site web site name + @type str + @return zoom value for the site + @rtype int + """ + self.load() + + if site not in self.__zoomDB: + return None + + return self.__zoomDB[site] + + +__ZoomManager = None + + +def instance(): + """ + Global function to get a reference to the zoom manager and create it, if + it hasn't been yet. + + @return reference to the zoom manager object + @rtype ZoomManager + """ + global __ZoomManager + + if __ZoomManager is None: + __ZoomManager = ZoomManager() + + return __ZoomManager
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/ZoomManager/ZoomValuesDialog.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show all saved zoom values. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QSortFilterProxyModel +from PyQt5.QtGui import QFont, QFontMetrics +from PyQt5.QtWidgets import QDialog + +from .Ui_ZoomValuesDialog import Ui_ZoomValuesDialog + + +class ZoomValuesDialog(QDialog, Ui_ZoomValuesDialog): + """ + Class implementing a dialog to show all saved zoom values. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + """ + super(ZoomValuesDialog, self).__init__(parent) + self.setupUi(self) + + self.removeButton.clicked.connect( + self.zoomValuesTable.removeSelected) + self.removeAllButton.clicked.connect(self.zoomValuesTable.removeAll) + + from . import ZoomManager + from .ZoomValuesModel import ZoomValuesModel + + self.zoomValuesTable.verticalHeader().hide() + self.__zoomValuesModel = ZoomValuesModel( + ZoomManager.instance(), self) + self.__proxyModel = QSortFilterProxyModel(self) + self.__proxyModel.setSourceModel(self.__zoomValuesModel) + self.searchEdit.textChanged.connect( + self.__proxyModel.setFilterFixedString) + self.zoomValuesTable.setModel(self.__proxyModel) + + fm = QFontMetrics(QFont()) + height = fm.height() + fm.height() // 3 + self.zoomValuesTable.verticalHeader().setDefaultSectionSize(height) + self.zoomValuesTable.verticalHeader().setMinimumSectionSize(-1) + + self.__calculateHeaderSizes() + + def __calculateHeaderSizes(self): + """ + Private method to calculate the section sizes of the horizontal header. + """ + fm = QFontMetrics(QFont()) + for section in range(self.__zoomValuesModel.columnCount()): + header = self.zoomValuesTable.horizontalHeader()\ + .sectionSizeHint(section) + if section == 0: + header = fm.width("extraveryveryverylongsitename") + elif section == 1: + header = fm.width("averagelongzoomvalue") + buffer = fm.width("mm") + header += buffer + self.zoomValuesTable.horizontalHeader()\ + .resizeSection(section, header) + self.zoomValuesTable.horizontalHeader().setStretchLastSection(True)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/ZoomManager/ZoomValuesDialog.ui Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ZoomValuesDialog</class> + <widget class="QDialog" name="ZoomValuesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>350</height> + </rect> + </property> + <property name="windowTitle"> + <string>Saved Zoom Values</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <item> + <widget class="E5ClearableLineEdit" name="searchEdit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Enter search term</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="E5TableView" name="zoomValuesTable"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> + <property name="showGrid"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QPushButton" name="removeButton"> + <property name="toolTip"> + <string>Press to remove the selected entries</string> + </property> + <property name="text"> + <string>&Remove</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="removeAllButton"> + <property name="toolTip"> + <string>Press to remove all entries</string> + </property> + <property name="text"> + <string>Remove &All</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>208</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5ClearableLineEdit</class> + <extends>QLineEdit</extends> + <header>E5Gui/E5LineEdit.h</header> + </customwidget> + <customwidget> + <class>E5TableView</class> + <extends>QTableView</extends> + <header>E5Gui/E5TableView.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>searchEdit</tabstop> + <tabstop>zoomValuesTable</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>removeAllButton</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ZoomValuesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>237</x> + <y>340</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ZoomValuesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>325</x> + <y>340</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/ZoomManager/ZoomValuesModel.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a model for zoom values management. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt, QModelIndex, QAbstractTableModel + + +class ZoomValuesModel(QAbstractTableModel): + """ + Class implementing a model for zoom values management. + """ + def __init__(self, manager, parent=None): + """ + Constructor + + @param manager reference to the zoom values manager (ZoomManager) + @param parent reference to the parent object (QObject) + """ + super(ZoomValuesModel, self).__init__(parent) + + self.__manager = manager + manager.changed.connect(self.__zoomValuesChanged) + + self.__headers = [ + self.tr("Website"), + self.tr("Zoom Value [%]"), + ] + + def __zoomValuesChanged(self): + """ + Private slot handling a change of the registered zoom values. + """ + self.beginResetModel() + self.endResetModel() + + def removeRows(self, row, count, parent=QModelIndex()): + """ + Public method to remove entries from the model. + + @param row start row (integer) + @param count number of rows to remove (integer) + @param parent parent index (QModelIndex) + @return flag indicating success (boolean) + """ + if parent.isValid(): + return False + + if count <= 0: + return False + + lastRow = row + count - 1 + + self.beginRemoveRows(parent, row, lastRow) + + siteList = self.__manager.allSiteNames() + for index in range(row, lastRow + 1): + self.__manager.removeZoomValue(siteList[index]) + + return True + + def rowCount(self, parent=QModelIndex()): + """ + Public method to get the number of rows of the model. + + @param parent parent index (QModelIndex) + @return number of rows (integer) + """ + if parent.isValid(): + return 0 + else: + return self.__manager.sitesCount() + + def columnCount(self, parent=QModelIndex()): + """ + Public method to get the number of columns of the model. + + @param parent parent index (QModelIndex) + @return number of columns (integer) + """ + return len(self.__headers) + + def data(self, index, role): + """ + Public method to get data from the model. + + @param index index to get data for (QModelIndex) + @param role role of the data to retrieve (integer) + @return requested data + """ + if index.row() >= self.__manager.sitesCount() or index.row() < 0: + return None + + site = self.__manager.allSiteNames()[index.row()] + siteInfo = self.__manager.siteInfo(site) + + if siteInfo is None: + return None + + if role == Qt.DisplayRole: + if index.column() == 0: + return site + elif index.column() == 1: + return siteInfo + + return None + + def headerData(self, section, orientation, role=Qt.DisplayRole): + """ + Public method to get the header data. + + @param section section number (integer) + @param orientation header orientation (Qt.Orientation) + @param role data role (integer) + @return header data + """ + if orientation == Qt.Horizontal and role == Qt.DisplayRole: + try: + return self.__headers[section] + except IndexError: + pass + + return None
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/ZoomManager/__init__.py Sun Feb 07 18:08:48 2016 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing a manager for site specific zoom level settings. +"""
--- a/eric6.e4p Sat Feb 06 17:43:59 2016 +0100 +++ b/eric6.e4p Sun Feb 07 18:08:48 2016 +0100 @@ -1267,12 +1267,16 @@ <Source>WebBrowser/JavaScript/AutoFillJsObject.py</Source> <Source>WebBrowser/JavaScript/ExternalJsObject.py</Source> <Source>WebBrowser/JavaScript/__init__.py</Source> + <Source>WebBrowser/Network/FollowRedirectReply.py</Source> <Source>WebBrowser/Network/NetworkManager.py</Source> <Source>WebBrowser/Network/__init__.py</Source> <Source>WebBrowser/SearchWidget.py</Source> <Source>WebBrowser/Tools/Scripts.py</Source> <Source>WebBrowser/Tools/WebBrowserTools.py</Source> + <Source>WebBrowser/Tools/WebIconLoader.py</Source> + <Source>WebBrowser/Tools/WebIconProvider.py</Source> <Source>WebBrowser/Tools/__init__.py</Source> + <Source>WebBrowser/UrlBar/FavIconLabel.py</Source> <Source>WebBrowser/UrlBar/StackedUrlBar.py</Source> <Source>WebBrowser/UrlBar/UrlBar.py</Source> <Source>WebBrowser/UrlBar/__init__.py</Source> @@ -1281,6 +1285,10 @@ <Source>WebBrowser/WebBrowserTabWidget.py</Source> <Source>WebBrowser/WebBrowserView.py</Source> <Source>WebBrowser/WebBrowserWindow.py</Source> + <Source>WebBrowser/ZoomManager/ZoomManager.py</Source> + <Source>WebBrowser/ZoomManager/ZoomValuesDialog.py</Source> + <Source>WebBrowser/ZoomManager/ZoomValuesModel.py</Source> + <Source>WebBrowser/ZoomManager/__init__.py</Source> <Source>WebBrowser/__init__.py</Source> <Source>WebBrowser/data/javascript_rc.py</Source> <Source>__init__.py</Source> @@ -1681,6 +1689,7 @@ <Form>VCS/RepositoryInfoDialog.ui</Form> <Form>ViewManager/BookmarkedFilesDialog.ui</Form> <Form>WebBrowser/SearchWidget.ui</Form> + <Form>WebBrowser/ZoomManager/ZoomValuesDialog.ui</Form> </Forms> <Translations> <Translation>i18n/eric6_cs.qm</Translation>
--- a/eric6_browser.py Sat Feb 06 17:43:59 2016 +0100 +++ b/eric6_browser.py Sun Feb 07 18:08:48 2016 +0100 @@ -31,11 +31,20 @@ import os # TODO: adjust this when done -MIN_QT_VERSION = "5.5.0" +MIN_QT_VERSION = "5.6.0" from PyQt5.QtCore import qVersion if qVersion() < MIN_QT_VERSION: - print("You need at least Qt Version {0} to execute the web browser." + try: # Py2 + import tkMessageBox as messagebox + except ImportError: + try: # Py3 + from tkinter import messagebox + except ImportError: + sys.exit(100) + messagebox.showerror( + "eric6 Error", + "You need at least Qt Version {0} to execute the web browser." .format(MIN_QT_VERSION)) sys.exit(100)