Sat, 12 Mar 2016 16:49:36 +0100
Continued porting the web browser.
- added cookies stuff
--- a/Preferences/__init__.py Fri Mar 11 19:49:18 2016 +0100 +++ b/Preferences/__init__.py Sat Mar 12 16:49:36 2016 +0100 @@ -1036,6 +1036,9 @@ "DoNotTrack": False, "SendReferer": True, "SendRefererWhitelist": ["qt-apps.org", "kde-apps.org"], + "AcceptCookies": 2, # CookieJar.AcceptOnlyFromSitesNavigatedTo + "KeepCookiesUntil": 0, # CookieJar.KeepUntilExpire + "FilterTrackingCookies": True, # Grease Monkey "GreaseMonkeyDisabledScripts": [], # Downloads @@ -2781,8 +2784,7 @@ ## if QWebSettings is None: ## value = prefClass.helpDefaults[key] ## return value -## elif key in ["AcceptCookies", -## "KeepCookiesUntil", "StartupBehavior", +## elif key in ["StartupBehavior", ## "OfflineStorageDatabaseQuota", ## "OfflineWebApplicationCacheQuota", "CachePolicy", ## "AdBlockUpdatePeriod", @@ -2793,11 +2795,11 @@ "SearchLanguage", "WebInspectorPort", "DefaultFontSize", "DefaultFixedFontSize", "MinimumFontSize", "MinimumLogicalFontSize", - "DiskCacheSize", ]: + "DiskCacheSize", "AcceptCookies", "KeepCookiesUntil", + ]: return int(prefClass.settings.value( "WebBrowser/" + key, prefClass.webBrowserDefaults[key])) -## elif key in ["DiskCacheEnabled", "FilterTrackingCookies", -## "PrintBackgrounds", "AdBlockEnabled" +## elif key in ["PrintBackgrounds", "AdBlockEnabled" ## "JavaEnabled", ## "JavaScriptCanCloseWindows", ## "PluginsEnabled", "DnsPrefetchEnabled", @@ -2819,7 +2821,7 @@ "SyncPasswords", "SyncUserAgents", "SyncSpeedDial", "SyncEncryptData", "SyncEncryptPasswordsOnly", "ShowPreview", "WebInspectorEnabled", "DiskCacheEnabled", - "DoNotTrack", "SendReferer", + "DoNotTrack", "SendReferer", "FilterTrackingCookies", ]: return toBool(prefClass.settings.value( "WebBrowser/" + key, prefClass.webBrowserDefaults[key]))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookieDetailsDialog.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog showing the cookie data. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QDialog + +from .Ui_CookieDetailsDialog import Ui_CookieDetailsDialog + + +class CookieDetailsDialog(QDialog, Ui_CookieDetailsDialog): + """ + Class implementing a dialog showing the cookie data. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QWidget) + """ + super(CookieDetailsDialog, self).__init__(parent) + self.setupUi(self) + self.setWindowFlags(Qt.Window) + + def setData(self, domain, name, path, secure, expires, value): + """ + Public method to set the data to be shown. + + @param domain domain of the cookie (string) + @param name name of the cookie (string) + @param path path of the cookie (string) + @param secure flag indicating a secure cookie (boolean) + @param expires expiration time of the cookie (string) + @param value value of the cookie (string) + """ + self.domainEdit.setText(domain) + self.nameEdit.setText(name) + self.pathEdit.setText(path) + self.secureCheckBox.setChecked(secure) + self.expirationEdit.setText(expires) + self.valueEdit.setPlainText(value)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookieDetailsDialog.ui Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookieDetailsDialog</class> + <widget class="QDialog" name="CookieDetailsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Cookie Details</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Domain:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="domainEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="nameEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Path:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="pathEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Secure:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QCheckBox" name="secureCheckBox"> + <property name="text"> + <string/> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Expires:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="expirationEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Contents:</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QPlainTextEdit" name="valueEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </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> + <tabstops> + <tabstop>domainEdit</tabstop> + <tabstop>nameEdit</tabstop> + <tabstop>pathEdit</tabstop> + <tabstop>secureCheckBox</tabstop> + <tabstop>expirationEdit</tabstop> + <tabstop>valueEdit</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>CookieDetailsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>CookieDetailsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</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/CookieJar/CookieExceptionsModel.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,231 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the cookie exceptions model. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt, QAbstractTableModel, QSize, QModelIndex +from PyQt5.QtGui import QFont, QFontMetrics + + +class CookieExceptionsModel(QAbstractTableModel): + """ + Class implementing the cookie exceptions model. + """ + def __init__(self, cookieJar, parent=None): + """ + Constructor + + @param cookieJar reference to the cookie jar (CookieJar) + @param parent reference to the parent object (QObject) + """ + super(CookieExceptionsModel, self).__init__(parent) + + self.__cookieJar = cookieJar + self.__allowedCookies = self.__cookieJar.allowedCookies() + self.__blockedCookies = self.__cookieJar.blockedCookies() + self.__sessionCookies = self.__cookieJar.allowForSessionCookies() + + self.__headers = [ + self.tr("Website"), + self.tr("Status"), + ] + + def headerData(self, section, orientation, role): + """ + Public method to get header data from the model. + + @param section section number (integer) + @param orientation orientation (Qt.Orientation) + @param role role of the data to retrieve (integer) + @return requested data + """ + if role == Qt.SizeHintRole: + fm = QFontMetrics(QFont()) + height = fm.height() + fm.height() // 3 + width = \ + fm.width(self.headerData(section, orientation, Qt.DisplayRole)) + return QSize(width, height) + + if orientation == Qt.Horizontal and role == Qt.DisplayRole: + try: + return self.__headers[section] + except IndexError: + return None + + return QAbstractTableModel.headerData(self, section, orientation, role) + + 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() < 0 or index.row() >= self.rowCount(): + return None + + if role in (Qt.DisplayRole, Qt.EditRole): + row = index.row() + if row < len(self.__allowedCookies): + if index.column() == 0: + return self.__allowedCookies[row] + elif index.column() == 1: + return self.tr("Allow") + else: + return None + + row -= len(self.__allowedCookies) + if row < len(self.__blockedCookies): + if index.column() == 0: + return self.__blockedCookies[row] + elif index.column() == 1: + return self.tr("Block") + else: + return None + + row -= len(self.__blockedCookies) + if row < len(self.__sessionCookies): + if index.column() == 0: + return self.__sessionCookies[row] + elif index.column() == 1: + return self.tr("Allow For Session") + else: + return None + + return None + + return None + + 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) + """ + if parent.isValid(): + return 0 + else: + return len(self.__headers) + + 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() or self.__cookieJar is None: + return 0 + else: + return len(self.__allowedCookies) + \ + len(self.__blockedCookies) + \ + len(self.__sessionCookies) + + 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() or self.__cookieJar is None: + return False + + lastRow = row + count - 1 + self.beginRemoveRows(parent, row, lastRow) + for i in range(lastRow, row - 1, -1): + rowToRemove = i + + if rowToRemove < len(self.__allowedCookies): + del self.__allowedCookies[rowToRemove] + continue + + rowToRemove -= len(self.__allowedCookies) + if rowToRemove < len(self.__blockedCookies): + del self.__blockedCookies[rowToRemove] + continue + + rowToRemove -= len(self.__blockedCookies) + if rowToRemove < len(self.__sessionCookies): + del self.__sessionCookies[rowToRemove] + continue + + self.__cookieJar.setAllowedCookies(self.__allowedCookies) + self.__cookieJar.setBlockedCookies(self.__blockedCookies) + self.__cookieJar.setAllowForSessionCookies(self.__sessionCookies) + self.endRemoveRows() + + return True + + def addRule(self, host, rule): + """ + Public method to add an exception rule. + + @param host name of the host to add a rule for (string) + @param rule type of rule to add (CookieJar.Allow, CookieJar.Block or + CookieJar.AllowForSession) + """ + if not host: + return + + from .CookieJar import CookieJar + + if rule == CookieJar.Allow: + self.__addHost( + host, self.__allowedCookies, self.__blockedCookies, + self.__sessionCookies) + return + elif rule == CookieJar.Block: + self.__addHost( + host, self.__blockedCookies, self.__allowedCookies, + self.__sessionCookies) + return + elif rule == CookieJar.AllowForSession: + self.__addHost( + host, self.__sessionCookies, self.__allowedCookies, + self.__blockedCookies) + return + + def __addHost(self, host, addList, removeList1, removeList2): + """ + Private method to add a host to an exception list. + + @param host name of the host to add (string) + @param addList reference to the list to add it to (list of strings) + @param removeList1 reference to first list to remove it from + (list of strings) + @param removeList2 reference to second list to remove it from + (list of strings) + """ + if host not in addList: + addList.append(host) + if host in removeList1: + removeList1.remove(host) + if host in removeList2: + removeList2.remove(host) + + # Avoid to have similar rules (with or without leading dot) + # e.g. python-projects.org and .python-projects.org + if host.startswith("."): + otherRule = host[1:] + else: + otherRule = '.' + host + if otherRule in addList: + addList.remove(otherRule) + if otherRule in removeList1: + removeList1.remove(otherRule) + if otherRule in removeList2: + removeList2.remove(otherRule) + + self.beginResetModel() + self.endResetModel()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookieJar.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,435 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a QNetworkCookieJar subclass with various accept policies. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QSettings +from PyQt5.QtNetwork import QNetworkCookieJar, QNetworkCookie + +from WebBrowser.WebBrowserWindow import WebBrowserWindow + +from Utilities.AutoSaver import AutoSaver +import Utilities +import Preferences + + +class CookieJar(QNetworkCookieJar): + """ + Class implementing a QNetworkCookieJar subclass with various accept + policies. + + @signal cookiesChanged() emitted after the cookies have been changed + """ + cookiesChanged = pyqtSignal() + + AcceptAlways = 0 + AcceptNever = 1 + AcceptOnlyFromSitesNavigatedTo = 2 + AcceptMax = 2 + + KeepUntilExpire = 0 + KeepUntilExit = 1 + KeepMax = 1 + + Allow = 0 + Block = 1 + AllowForSession = 2 + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QObject) + """ + super(CookieJar, self).__init__(parent) + + self.__loaded = False + self.__acceptCookies = self.AcceptOnlyFromSitesNavigatedTo + self.__saveTimer = AutoSaver(self, self.__save) + + self.__cookies = [] + + self.__cookiesFile = os.path.join(Utilities.getConfigDir(), + "web_browser", "cookies.ini") + self.__load() + + # TODO: Qt 5.6 +## self.__store = WebBrowserWindow.webProfile.cookieStore() +## self.__store.cookieAdded.connect(self.__cookieAdded) +## self.__store.cookieRemoved.connect(self.__cookieRemoved) + + def close(self): + """ + Public slot to close the cookie jar. + """ + if not self.__loaded: + self.__load() + + if self.__keepCookies == self.KeepUntilExit: + self.clear() + self.__saveTimer.saveIfNeccessary() + + def clear(self): + """ + Public method to clear all cookies. + """ + if not self.__loaded: + self.__load() + + self.__cookies = [] + # TODO: Qt 5.6 +## self.__store.deleteAllCookies() + self.cookiesChanged.emit() + + def removeCookies(self, cookies): + """ + Public method to remove a cookie. + + @param cookies list of cookies to be removed + @type list of QNetworkCookie + """ + wasBlocked = self.blockSignals(True) + # TODO: Qt 5.6 +## for cookie in cookies: +## self.__store.deleteCookie(cookie) + self.blockSignals(wasBlocked) + + self.cookiesChanged.emit() + + def __load(self): + """ + Private method to load the cookies settings. + """ + if self.__loaded: + return + + cookieSettings = QSettings(self.__cookiesFile, QSettings.IniFormat) + + # load exceptions + self.__exceptionsBlock = Preferences.toList( + cookieSettings.value("Exceptions/block")) + self.__exceptionsAllow = Preferences.toList( + cookieSettings.value("Exceptions/allow")) + self.__exceptionsAllowForSession = Preferences.toList( + cookieSettings.value("Exceptions/allowForSession")) + self.__exceptionsBlock.sort() + self.__exceptionsAllow.sort() + self.__exceptionsAllowForSession.sort() + + self.__acceptCookies = Preferences.getWebBrowser("AcceptCookies") + self.__keepCookies = Preferences.getWebBrowser("KeepCookiesUntil") + if self.__keepCookies == self.KeepUntilExit: + self.clear() + + self.__filterTrackingCookies = Preferences.toBool( + Preferences.getWebBrowser("FilterTrackingCookies")) + + self.__loaded = True + self.cookiesChanged.emit() + + def __save(self): + """ + Private method to save the cookies settings. + """ + if not self.__loaded: + return + + cookieSettings = QSettings(self.__cookiesFile, QSettings.IniFormat) + + cookieSettings.setValue("Exceptions/block", self.__exceptionsBlock) + cookieSettings.setValue("Exceptions/allow", self.__exceptionsAllow) + cookieSettings.setValue("Exceptions/allowForSession", + self.__exceptionsAllowForSession) + + Preferences.setWebBrowser("AcceptCookies", self.__acceptCookies) + Preferences.setWebBrowser("KeepCookiesUntil", self.__keepCookies) + Preferences.setWebBrowser("FilterTrackingCookies", + self.__filterTrackingCookies) + + @pyqtSlot(QNetworkCookie) + def __cookieAdded(self, cookie): + """ + Private slot handling the addition of a cookie. + + @param cookie cookie which was added + @type QNetworkCookie + """ + if self.__rejectCookie(cookie, cookie.domain()): + # TODO: Qt 5.6 +## self.__store.deleteCookie(cookie) + return + + self.__cookies.append(cookie) + self.cookiesChanged.emit() + + @pyqtSlot(QNetworkCookie) + def __cookieRemoved(self, cookie): + """ + Private slot handling the removal of a cookie. + + @param cookie cookie which was removed + @type QNetworkCookie + """ + if cookie in self.__cookies: + self.__cookies.remove(cookie) + self.cookiesChanged.emit() + + def __rejectCookie(self, cookie, cookieDomain): + """ + Public method to test, if a cookie shall be rejected. + + @param cookie cookie to be tested + @type QNetworkCookie + @param cookieDomain domain of the cookie + @type str + @return flag indicating the cookie shall be rejected + @rtype bool + """ + if not self.__loaded: + self.__load() + + eBlock = self.__isOnDomainList(self.__exceptionsBlock, cookieDomain) + eAllow = not eBlock and \ + self.__isOnDomainList(self.__exceptionsAllow, cookieDomain) + eAllowSession = not eBlock and \ + not eAllow and \ + self.__isOnDomainList( + self.__exceptionsAllowForSession, cookieDomain) + + if self.__acceptCookies == self.AcceptNever: + if not eAllow and not eAllowSession: + return True + + if self.__acceptCookies == self.AcceptAlways: + if eBlock: + return True + + if self.__acceptCookies == self.AcceptOnlyFromSitesNavigatedTo: + url = WebBrowserWindow.mainWindow().getWindow().currentBrowser()\ + .url() + if url.isValid(): + host = url.host() + else: + host = "" + if not self.__matchDomain(cookieDomain, host): + return True + + if self.__filterTrackingCookies and cookie.name().startsWith(b"__utm"): + return True + + return False + + def acceptPolicy(self): + """ + Public method to get the accept policy. + + @return current accept policy + """ + if not self.__loaded: + self.__load() + + return self.__acceptCookies + + def setAcceptPolicy(self, policy): + """ + Public method to set the accept policy. + + @param policy accept policy to be set + """ + if not self.__loaded: + self.__load() + + if policy > self.AcceptMax: + return + if policy == self.__acceptCookies: + return + + self.__acceptCookies = policy + self.__saveTimer.changeOccurred() + + def keepPolicy(self): + """ + Public method to get the keep policy. + + @return keep policy + """ + if not self.__loaded: + self.__load() + + return self.__keepCookies + + def setKeepPolicy(self, policy): + """ + Public method to set the keep policy. + + @param policy keep policy to be set + """ + if not self.__loaded: + self.__load() + + if policy > self.KeepMax: + return + if policy == self.__keepCookies: + return + + self.__keepCookies = policy + self.__saveTimer.changeOccurred() + + def blockedCookies(self): + """ + Public method to return the list of blocked domains. + + @return list of blocked domains (list of strings) + """ + if not self.__loaded: + self.__load() + + return self.__exceptionsBlock + + def allowedCookies(self): + """ + Public method to return the list of allowed domains. + + @return list of allowed domains (list of strings) + """ + if not self.__loaded: + self.__load() + + return self.__exceptionsAllow + + def allowForSessionCookies(self): + """ + Public method to return the list of allowed session cookie domains. + + @return list of allowed session cookie domains (list of strings) + """ + if not self.__loaded: + self.__load() + + return self.__exceptionsAllowForSession + + def setBlockedCookies(self, list_): + """ + Public method to set the list of blocked domains. + + @param list_ list of blocked domains (list of strings) + """ + if not self.__loaded: + self.__load() + + self.__exceptionsBlock = list_[:] + self.__exceptionsBlock.sort() + self.__saveTimer.changeOccurred() + + def setAllowedCookies(self, list_): + """ + Public method to set the list of allowed domains. + + @param list_ list of allowed domains (list of strings) + """ + if not self.__loaded: + self.__load() + + self.__exceptionsAllow = list_[:] + self.__exceptionsAllow.sort() + self.__saveTimer.changeOccurred() + + def setAllowForSessionCookies(self, list_): + """ + Public method to set the list of allowed session cookie domains. + + @param list_ list of allowed session cookie domains (list of strings) + """ + if not self.__loaded: + self.__load() + + self.__exceptionsAllowForSession = list_[:] + self.__exceptionsAllowForSession.sort() + self.__saveTimer.changeOccurred() + + def filterTrackingCookies(self): + """ + Public method to get the filter tracking cookies flag. + + @return filter tracking cookies flag (boolean) + """ + return self.__filterTrackingCookies + + def setFilterTrackingCookies(self, filterTrackingCookies): + """ + Public method to set the filter tracking cookies flag. + + @param filterTrackingCookies filter tracking cookies flag (boolean) + """ + self.__filterTrackingCookies = filterTrackingCookies + + def __isOnDomainList(self, rules, domain): + """ + Private method to check, if either the rule matches the domain exactly + or the domain ends with ".rule". + + @param rules list of rules (list of strings) + @param domain domain name to check (string) + @return flag indicating a match (boolean) + """ + for rule in rules: + if rule.startswith("."): + if domain.endswith(rule): + return True + + withoutDot = rule[1:] + if domain == withoutDot: + return True + else: + domainEnding = domain[-(len(rule) + 1):] + if domainEnding and \ + domainEnding[0] == "." and \ + domain.endswith(rule): + return True + + if rule == domain: + return True + + return False + + def __matchDomain(self, cookieDomain, siteDomain): + """ + Private method to check, if a URLs host matches a cookie domain + according to RFC 6265. + + @param cookieDomain domain of the cookie + @type str + @param siteDomain domain or host of an URL + @type str + @return flag indicating a match + @rtype bool + """ + if cookieDomain.startswith("."): + cookieDomain = cookieDomain[1:] + if siteDomain.startswith("."): + siteDomain = siteDomain[1:] + + if cookieDomain == siteDomain: + return True + + if not siteDomain.endswith(cookieDomain): + return False + + index = siteDomain.find(cookieDomain) + return index > 0 and siteDomain[index - 1] == "." + + def cookies(self): + """ + Public method to get the cookies of the cookie jar. + + @return list of all cookies (list of QNetworkCookie) + """ + return self.__cookies
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookieModel.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the cookie model. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt, QAbstractTableModel, QSize, QModelIndex +from PyQt5.QtGui import QFont, QFontMetrics + + +class CookieModel(QAbstractTableModel): + """ + Class implementing the cookie model. + """ + def __init__(self, cookieJar, parent=None): + """ + Constructor + + @param cookieJar reference to the cookie jar (CookieJar) + @param parent reference to the parent object (QObject) + """ + super(CookieModel, self).__init__(parent) + + self.__headers = [ + self.tr("Website"), + self.tr("Name"), + self.tr("Path"), + self.tr("Secure"), + self.tr("Expires"), + ] + self.__cookieJar = cookieJar + self.__cookieJar.cookiesChanged.connect(self.__cookiesChanged) + + def headerData(self, section, orientation, role): + """ + Public method to get header data from the model. + + @param section section number (integer) + @param orientation orientation (Qt.Orientation) + @param role role of the data to retrieve (integer) + @return requested data + """ + if role == Qt.SizeHintRole: + fm = QFontMetrics(QFont()) + height = fm.height() + fm.height() // 3 + width = \ + fm.width(self.headerData(section, orientation, Qt.DisplayRole)) + return QSize(width, height) + + if orientation == Qt.Horizontal: + if role == Qt.DisplayRole: + try: + return self.__headers[section] + except IndexError: + return None + + return None + + return QAbstractTableModel.headerData(self, section, orientation, role) + + 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 + """ + lst = [] + if self.__cookieJar is not None: + lst = self.__cookieJar.cookies() + if index.row() < 0 or index.row() >= len(lst): + return None + + if role in (Qt.DisplayRole, Qt.EditRole): + cookie = lst[index.row()] + col = index.column() + if col == 0: + return cookie.domain() + elif col == 1: + return bytes(cookie.name()).decode() + elif col == 2: + return cookie.path() + elif col == 3: + return cookie.isSecure() + elif col == 4: + return cookie.expirationDate() + elif col == 5: + return cookie.value() + else: + return None + + return None + + 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) + """ + if parent.isValid(): + return 0 + else: + return len(self.__headers) + + def rowCount(self, parent=QModelIndex()): + """ + Public method to get the number of rows of the model. + + @param parent parent index (QModelIndex) + @return number of columns (integer) + """ + if parent.isValid() or self.__cookieJar is None: + return 0 + else: + return len(self.__cookieJar.cookies()) + + 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() or self.__cookieJar is None: + return False + + lst = self.__cookieJar.cookies()[row:row + count] + self.__cookieJar.removeCookies(lst) + + return True + + def __cookiesChanged(self): + """ + Private slot handling changes of the cookies list in the cookie jar. + """ + self.beginResetModel() + self.endResetModel()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookiesConfigurationDialog.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the cookies configuration dialog. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot +from PyQt5.QtWidgets import QDialog + +from .CookieJar import CookieJar + +from .Ui_CookiesConfigurationDialog import Ui_CookiesConfigurationDialog + + +class CookiesConfigurationDialog(QDialog, Ui_CookiesConfigurationDialog): + """ + Class implementing the cookies configuration dialog. + """ + def __init__(self, parent): + """ + Constructor + + @param parent reference to the parent object (QWidget) + """ + super(CookiesConfigurationDialog, self).__init__(parent) + self.setupUi(self) + + self.__mw = parent + + jar = self.__mw.cookieJar() + acceptPolicy = jar.acceptPolicy() + if acceptPolicy == CookieJar.AcceptAlways: + self.acceptCombo.setCurrentIndex(0) + elif acceptPolicy == CookieJar.AcceptNever: + self.acceptCombo.setCurrentIndex(1) + elif acceptPolicy == CookieJar.AcceptOnlyFromSitesNavigatedTo: + self.acceptCombo.setCurrentIndex(2) + + keepPolicy = jar.keepPolicy() + if keepPolicy == CookieJar.KeepUntilExpire: + self.keepUntilCombo.setCurrentIndex(0) + elif keepPolicy == CookieJar.KeepUntilExit: + self.keepUntilCombo.setCurrentIndex(1) + + self.filterTrackingCookiesCheckbox.setChecked( + jar.filterTrackingCookies()) + + msh = self.minimumSizeHint() + self.resize(max(self.width(), msh.width()), msh.height()) + + def accept(self): + """ + Public slot to accept the dialog. + """ + acceptSelection = self.acceptCombo.currentIndex() + if acceptSelection == 0: + acceptPolicy = CookieJar.AcceptAlways + elif acceptSelection == 1: + acceptPolicy = CookieJar.AcceptNever + elif acceptSelection == 2: + acceptPolicy = CookieJar.AcceptOnlyFromSitesNavigatedTo + + keepSelection = self.keepUntilCombo.currentIndex() + if keepSelection == 0: + keepPolicy = CookieJar.KeepUntilExpire + elif keepSelection == 1: + keepPolicy = CookieJar.KeepUntilExit + + jar = self.__mw.cookieJar() + jar.setAcceptPolicy(acceptPolicy) + jar.setKeepPolicy(keepPolicy) + jar.setFilterTrackingCookies( + self.filterTrackingCookiesCheckbox.isChecked()) + + super(CookiesConfigurationDialog, self).accept() + + @pyqtSlot() + def on_exceptionsButton_clicked(self): + """ + Private slot to show the cookies exceptions dialog. + """ + from .CookiesExceptionsDialog import CookiesExceptionsDialog + dlg = CookiesExceptionsDialog(self.__mw.cookieJar()) + dlg.exec_() + + @pyqtSlot() + def on_cookiesButton_clicked(self): + """ + Private slot to show the cookies dialog. + """ + from .CookiesDialog import CookiesDialog + dlg = CookiesDialog(self.__mw.cookieJar()) + dlg.exec_()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookiesConfigurationDialog.ui Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,200 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookiesConfigurationDialog</class> + <widget class="QDialog" name="CookiesConfigurationDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>160</height> + </rect> + </property> + <property name="windowTitle"> + <string>Configure cookies</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="headerLabel"> + <property name="text"> + <string><b>Configure cookies</b></string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line17"> + <property name="frameShape"> + <enum>QFrame::HLine</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>&Accept Cookies:</string> + </property> + <property name="buddy"> + <cstring>acceptCombo</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="acceptCombo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select the accept policy</string> + </property> + <item> + <property name="text"> + <string>Always</string> + </property> + </item> + <item> + <property name="text"> + <string>Never</string> + </property> + </item> + <item> + <property name="text"> + <string>Only from sites you navigate to</string> + </property> + </item> + </widget> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="exceptionsButton"> + <property name="toolTip"> + <string>Show a dialog to configure exceptions</string> + </property> + <property name="text"> + <string>&Exceptions...</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>&Keep until:</string> + </property> + <property name="buddy"> + <cstring>keepUntilCombo</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="keepUntilCombo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select the keep policy</string> + </property> + <item> + <property name="text"> + <string>They expire</string> + </property> + </item> + <item> + <property name="text"> + <string>I exit the application</string> + </property> + </item> + </widget> + </item> + <item row="1" column="2"> + <widget class="QPushButton" name="cookiesButton"> + <property name="toolTip"> + <string>Show a dialog listing all cookies</string> + </property> + <property name="text"> + <string>&Show Cookies...</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="filterTrackingCookiesCheckbox"> + <property name="toolTip"> + <string>Select to filter tracking cookies</string> + </property> + <property name="text"> + <string>&Filter Tracking Cookies</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>acceptCombo</tabstop> + <tabstop>exceptionsButton</tabstop> + <tabstop>keepUntilCombo</tabstop> + <tabstop>cookiesButton</tabstop> + <tabstop>filterTrackingCookiesCheckbox</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>CookiesConfigurationDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>CookiesConfigurationDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</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/CookieJar/CookiesDialog.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show all cookies. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, Qt, QDateTime, QByteArray, \ + QSortFilterProxyModel +from PyQt5.QtGui import QFont, QFontMetrics +from PyQt5.QtWidgets import QDialog + +from .CookieModel import CookieModel + +from .Ui_CookiesDialog import Ui_CookiesDialog + + +class CookiesDialog(QDialog, Ui_CookiesDialog): + """ + Class implementing a dialog to show all cookies. + """ + def __init__(self, cookieJar, parent=None): + """ + Constructor + + @param cookieJar reference to the cookie jar (CookieJar) + @param parent reference to the parent widget (QWidget) + """ + super(CookiesDialog, self).__init__(parent) + self.setupUi(self) + + self.addButton.setEnabled(False) + + self.__cookieJar = cookieJar + + self.removeButton.clicked.connect(self.cookiesTable.removeSelected) + self.removeAllButton.clicked.connect(self.cookiesTable.removeAll) + + self.cookiesTable.verticalHeader().hide() + model = CookieModel(cookieJar, self) + self.__proxyModel = QSortFilterProxyModel(self) + self.__proxyModel.setSourceModel(model) + self.searchEdit.textChanged.connect( + self.__proxyModel.setFilterFixedString) + self.cookiesTable.setModel(self.__proxyModel) + self.cookiesTable.doubleClicked.connect(self.__showCookieDetails) + self.cookiesTable.selectionModel().selectionChanged.connect( + self.__tableSelectionChanged) + self.cookiesTable.model().modelReset.connect(self.__tableModelReset) + + fm = QFontMetrics(QFont()) + height = fm.height() + fm.height() // 3 + self.cookiesTable.verticalHeader().setDefaultSectionSize(height) + self.cookiesTable.verticalHeader().setMinimumSectionSize(-1) + for section in range(model.columnCount()): + header = self.cookiesTable.horizontalHeader()\ + .sectionSizeHint(section) + if section == 0: + header = fm.width("averagebiglonghost.averagedomain.info") + elif section == 1: + header = fm.width("_session_id") + elif section == 4: + header = fm.width( + QDateTime.currentDateTime().toString(Qt.LocalDate)) + buffer = fm.width("mm") + header += buffer + self.cookiesTable.horizontalHeader().resizeSection(section, header) + self.cookiesTable.horizontalHeader().setStretchLastSection(True) + self.cookiesTable.model().sort( + self.cookiesTable.horizontalHeader().sortIndicatorSection(), + Qt.AscendingOrder) + + self.__detailsDialog = None + + def __showCookieDetails(self, index): + """ + Private slot to show a dialog with the cookie details. + + @param index index of the entry to show (QModelIndex) + """ + if not index.isValid(): + return + + cookiesTable = self.sender() + if cookiesTable is None: + return + + model = cookiesTable.model() + row = index.row() + + domain = model.data(model.index(row, 0)) + name = model.data(model.index(row, 1)) + path = model.data(model.index(row, 2)) + secure = model.data(model.index(row, 3)) + expires = model.data(model.index(row, 4)).toString("yyyy-MM-dd hh:mm") + value = bytes( + QByteArray.fromPercentEncoding( + model.data(model.index(row, 5)))).decode() + + if self.__detailsDialog is None: + from .CookieDetailsDialog import CookieDetailsDialog + self.__detailsDialog = CookieDetailsDialog(self) + self.__detailsDialog.setData(domain, name, path, secure, expires, + value) + self.__detailsDialog.show() + + @pyqtSlot() + def on_addButton_clicked(self): + """ + Private slot to add a new exception. + """ + selection = self.cookiesTable.selectionModel().selectedRows() + if len(selection) == 0: + return + + from .CookiesExceptionsDialog import CookiesExceptionsDialog + + firstSelected = selection[0] + domainSelection = firstSelected.sibling(firstSelected.row(), 0) + domain = self.__proxyModel.data(domainSelection, Qt.DisplayRole) + dlg = CookiesExceptionsDialog(self.__cookieJar, self) + dlg.setDomainName(domain) + dlg.exec_() + + def __tableSelectionChanged(self, selected, deselected): + """ + Private slot to handle a change of selected items. + + @param selected selected indexes (QItemSelection) + @param deselected deselected indexes (QItemSelection) + """ + self.addButton.setEnabled(len(selected.indexes()) > 0) + + def __tableModelReset(self): + """ + Private slot to handle a reset of the cookies table. + """ + self.addButton.setEnabled(False)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookiesDialog.ui Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookiesDialog</class> + <widget class="QDialog" name="CookiesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>350</height> + </rect> + </property> + <property name="windowTitle"> + <string>Cookies</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" colspan="4"> + <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="minimumSize"> + <size> + <width>300</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Enter search term for cookies</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item row="1" column="0" colspan="4"> + <widget class="E5TableView" name="cookiesTable"> + <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 row="2" column="0"> + <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 row="2" column="1"> + <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 row="2" column="2"> + <widget class="QPushButton" name="addButton"> + <property name="toolTip"> + <string>Press to open the cookies exceptions dialog to add a new rule</string> + </property> + <property name="text"> + <string>Add R&ule...</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="3"> + <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> + <item row="3" column="0" colspan="4"> + <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>cookiesTable</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>removeAllButton</tabstop> + <tabstop>addButton</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>CookiesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>228</x> + <y>274</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>CookiesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</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/CookieJar/CookiesExceptionsDialog.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog for the configuration of cookie exceptions. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, QSortFilterProxyModel +from PyQt5.QtGui import QFont, QFontMetrics +from PyQt5.QtWidgets import QDialog, QCompleter + +from .CookieExceptionsModel import CookieExceptionsModel +from .CookieModel import CookieModel + +from .Ui_CookiesExceptionsDialog import Ui_CookiesExceptionsDialog + + +class CookiesExceptionsDialog(QDialog, Ui_CookiesExceptionsDialog): + """ + Class implementing a dialog for the configuration of cookie exceptions. + """ + def __init__(self, cookieJar, parent=None): + """ + Constructor + + @param cookieJar reference to the cookie jar (CookieJar) + @param parent reference to the parent widget (QWidget) + """ + super(CookiesExceptionsDialog, self).__init__(parent) + self.setupUi(self) + + self.__cookieJar = cookieJar + + self.removeButton.clicked.connect( + self.exceptionsTable.removeSelected) + self.removeAllButton.clicked.connect( + self.exceptionsTable.removeAll) + + self.exceptionsTable.verticalHeader().hide() + self.__exceptionsModel = CookieExceptionsModel(cookieJar) + self.__proxyModel = QSortFilterProxyModel(self) + self.__proxyModel.setSourceModel(self.__exceptionsModel) + self.searchEdit.textChanged.connect( + self.__proxyModel.setFilterFixedString) + self.exceptionsTable.setModel(self.__proxyModel) + + cookieModel = CookieModel(cookieJar, self) + self.domainEdit.setCompleter(QCompleter(cookieModel, self.domainEdit)) + + f = QFont() + f.setPointSize(10) + fm = QFontMetrics(f) + height = fm.height() + fm.height() // 3 + self.exceptionsTable.verticalHeader().setDefaultSectionSize(height) + self.exceptionsTable.verticalHeader().setMinimumSectionSize(-1) + for section in range(self.__exceptionsModel.columnCount()): + header = self.exceptionsTable.horizontalHeader()\ + .sectionSizeHint(section) + if section == 0: + header = fm.width("averagebiglonghost.averagedomain.info") + elif section == 1: + header = fm.width(self.tr("Allow For Session")) + buffer = fm.width("mm") + header += buffer + self.exceptionsTable.horizontalHeader()\ + .resizeSection(section, header) + + def setDomainName(self, domain): + """ + Public method to set the domain to be displayed. + + @param domain domain name to be displayed (string) + """ + self.domainEdit.setText(domain) + + @pyqtSlot(str) + def on_domainEdit_textChanged(self, txt): + """ + Private slot to handle a change of the domain edit text. + + @param txt current text of the edit (string) + """ + enabled = txt != "" + self.blockButton.setEnabled(enabled) + self.allowButton.setEnabled(enabled) + self.allowForSessionButton.setEnabled(enabled) + + @pyqtSlot() + def on_blockButton_clicked(self): + """ + Private slot to block cookies of a domain. + """ + from .CookieJar import CookieJar + self.__exceptionsModel.addRule(self.domainEdit.text(), CookieJar.Block) + self.domainEdit.clear() + + @pyqtSlot() + def on_allowForSessionButton_clicked(self): + """ + Private slot to allow cookies of a domain for the current session only. + """ + from .CookieJar import CookieJar + self.__exceptionsModel.addRule(self.domainEdit.text(), + CookieJar.AllowForSession) + self.domainEdit.clear() + + @pyqtSlot() + def on_allowButton_clicked(self): + """ + Private slot to allow cookies of a domain. + """ + from .CookieJar import CookieJar + self.__exceptionsModel.addRule(self.domainEdit.text(), CookieJar.Allow) + self.domainEdit.clear()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/CookieJar/CookiesExceptionsDialog.ui Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,292 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookiesExceptionsDialog</class> + <widget class="QDialog" name="CookiesExceptionsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>450</height> + </rect> + </property> + <property name="windowTitle"> + <string>Cookie Exceptions</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="newExceptionGroupBox"> + <property name="title"> + <string>New Exception</string> + </property> + <layout class="QGridLayout"> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>&Domain:</string> + </property> + <property name="buddy"> + <cstring>domainEdit</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="domainEdit"> + <property name="toolTip"> + <string>Enter the domain name</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <layout class="QHBoxLayout" name="_3"> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>81</width> + <height>25</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="blockButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to always reject cookies for the domain</string> + </property> + <property name="text"> + <string>&Block</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="allowForSessionButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to accept cookies for the domain for the current session</string> + </property> + <property name="text"> + <string>Allow For &Session</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="allowButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to always accept cookies for the domain</string> + </property> + <property name="text"> + <string>Allo&w</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="exceptionsGroup"> + <property name="title"> + <string>Exceptions</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" colspan="3"> + <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="minimumSize"> + <size> + <width>300</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Enter search term for exceptions</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item row="1" column="0" colspan="3"> + <widget class="E5TableView" name="exceptionsTable"> + <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> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> + <item row="2" column="0"> + <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 row="2" column="1"> + <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 row="2" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>286</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </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>domainEdit</tabstop> + <tabstop>blockButton</tabstop> + <tabstop>allowForSessionButton</tabstop> + <tabstop>allowButton</tabstop> + <tabstop>searchEdit</tabstop> + <tabstop>exceptionsTable</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>removeAllButton</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>CookiesExceptionsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>227</x> + <y>429</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>CookiesExceptionsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>295</x> + <y>435</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/CookieJar/__init__.py Sat Mar 12 16:49:36 2016 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing a cookie jar and related dialogs with models. +"""
--- a/WebBrowser/Network/NetworkManager.py Fri Mar 11 19:49:18 2016 +0100 +++ b/WebBrowser/Network/NetworkManager.py Sat Mar 12 16:49:36 2016 +0100 @@ -80,7 +80,7 @@ ## self.__interceptor = NetworkUrlInterceptor(self) ## WebBrowserWindow.webProfile().setRequestInterceptor(self.__interceptor) - # TODO: Cookie: create cookie jar + WebBrowserWindow.cookieJar() def __save(self): """
--- a/WebBrowser/WebBrowserWindow.py Fri Mar 11 19:49:18 2016 +0100 +++ b/WebBrowser/WebBrowserWindow.py Sat Mar 12 16:49:36 2016 +0100 @@ -84,7 +84,7 @@ _webProfile = None _networkManager = None -## _cookieJar = None + _cookieJar = None ## _helpEngine = None _bookmarksManager = None _historyManager = None @@ -1265,21 +1265,20 @@ self.__showAcceptedLanguages) self.__actions.append(self.acceptedLanguagesAct) - # TODO: Cookies -## self.cookiesAct = E5Action( -## self.tr('Cookies'), -## UI.PixmapCache.getIcon("cookie.png"), -## self.tr('C&ookies...'), 0, 0, self, 'webbrowser_cookies') -## self.cookiesAct.setStatusTip(self.tr( -## 'Configure cookies handling')) -## self.cookiesAct.setWhatsThis(self.tr( -## """<b>Cookies</b>""" -## """<p>Configure cookies handling.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.cookiesAct.triggered.connect( -## self.__showCookiesConfiguration) -## self.__actions.append(self.cookiesAct) + self.cookiesAct = E5Action( + self.tr('Cookies'), + UI.PixmapCache.getIcon("cookie.png"), + self.tr('C&ookies...'), 0, 0, self, 'webbrowser_cookies') + self.cookiesAct.setStatusTip(self.tr( + 'Configure cookies handling')) + self.cookiesAct.setWhatsThis(self.tr( + """<b>Cookies</b>""" + """<p>Configure cookies handling.</p>""" + )) + if not self.__initShortcutsOnly: + self.cookiesAct.triggered.connect( + self.__showCookiesConfiguration) + self.__actions.append(self.cookiesAct) self.flashCookiesAct = E5Action( self.tr('Flash Cookies'), @@ -1898,7 +1897,7 @@ menu.setTearOffEnabled(True) menu.addAction(self.prefAct) menu.addAction(self.acceptedLanguagesAct) -## menu.addAction(self.cookiesAct) + menu.addAction(self.cookiesAct) menu.addAction(self.flashCookiesAct) ## menu.addAction(self.offlineStorageAct) menu.addAction(self.personalDataAct) @@ -2048,7 +2047,7 @@ settingstb.setIconSize(UI.Config.ToolBarIconSize) settingstb.addAction(self.prefAct) settingstb.addAction(self.acceptedLanguagesAct) -## settingstb.addAction(self.cookiesAct) + settingstb.addAction(self.cookiesAct) settingstb.addAction(self.flashCookiesAct) ## settingstb.addAction(self.offlineStorageAct) settingstb.addAction(self.personalDataAct) @@ -2545,9 +2544,8 @@ # TODO: Network Monitor ## self.__closeNetworkMonitor() ## - # TODO: Cookies -## self.cookieJar().close() -## + self.cookieJar().close() + self.bookmarksToolBar.setModel(None) self.bookmarksManager().close() @@ -2872,15 +2870,14 @@ dlg.exec_() self.networkManager().languagesChanged() - # TODO: Cookies -## def __showCookiesConfiguration(self): -## """ -## Private slot to configure the cookies handling. -## """ -## from .CookieJar.CookiesConfigurationDialog import \ -## CookiesConfigurationDialog -## dlg = CookiesConfigurationDialog(self) -## dlg.exec_() + def __showCookiesConfiguration(self): + """ + Private slot to configure the cookies handling. + """ + from .CookieJar.CookiesConfigurationDialog import \ + CookiesConfigurationDialog + dlg = CookiesConfigurationDialog(self) + dlg.exec_() def __showFlashCookiesManagement(self): """ @@ -2941,18 +2938,19 @@ return cls._networkManager - # TODO: Cookies -## @classmethod -## def cookieJar(cls): -## """ -## Class method to get a reference to the cookie jar. -## -## @return reference to the cookie jar (CookieJar) -## """ -## from .CookieJar.CookieJar import CookieJar -## cls._cookieJar = CookieJar() -## return cls.networkManager().cookieJar() -## + @classmethod + def cookieJar(cls): + """ + Class method to get a reference to the cookie jar. + + @return reference to the cookie jar (CookieJar) + """ + if cls._cookieJar is None: + from .CookieJar.CookieJar import CookieJar + cls._cookieJar = CookieJar() + + return cls._cookieJar + def __clearIconsDatabase(self): """ Private slot to clear the favicons databse. @@ -3348,9 +3346,8 @@ cachePath = self.webProfile().cachePath() if cachePath: shutil.rmtree(cachePath) - # TODO: Cookies -## if cookies: -## self.cookieJar().clear() + if cookies: + self.cookieJar().clear() if passwords: self.passwordManager().clear() # TODO: Web Databases
--- a/eric6.e4p Fri Mar 11 19:49:18 2016 +0100 +++ b/eric6.e4p Sat Mar 12 16:49:36 2016 +0100 @@ -1291,6 +1291,14 @@ <Source>WebBrowser/Bookmarks/XbelWriter.py</Source> <Source>WebBrowser/Bookmarks/__init__.py</Source> <Source>WebBrowser/ClosedTabsManager.py</Source> + <Source>WebBrowser/CookieJar/CookieDetailsDialog.py</Source> + <Source>WebBrowser/CookieJar/CookieExceptionsModel.py</Source> + <Source>WebBrowser/CookieJar/CookieJar.py</Source> + <Source>WebBrowser/CookieJar/CookieModel.py</Source> + <Source>WebBrowser/CookieJar/CookiesConfigurationDialog.py</Source> + <Source>WebBrowser/CookieJar/CookiesDialog.py</Source> + <Source>WebBrowser/CookieJar/CookiesExceptionsDialog.py</Source> + <Source>WebBrowser/CookieJar/__init__.py</Source> <Source>WebBrowser/Download/DownloadAskActionDialog.py</Source> <Source>WebBrowser/Download/DownloadItem.py</Source> <Source>WebBrowser/Download/DownloadManager.py</Source> @@ -1819,6 +1827,10 @@ <Form>WebBrowser/Bookmarks/BookmarkPropertiesDialog.ui</Form> <Form>WebBrowser/Bookmarks/BookmarksDialog.ui</Form> <Form>WebBrowser/Bookmarks/BookmarksImportDialog.ui</Form> + <Form>WebBrowser/CookieJar/CookieDetailsDialog.ui</Form> + <Form>WebBrowser/CookieJar/CookiesConfigurationDialog.ui</Form> + <Form>WebBrowser/CookieJar/CookiesDialog.ui</Form> + <Form>WebBrowser/CookieJar/CookiesExceptionsDialog.ui</Form> <Form>WebBrowser/Download/DownloadAskActionDialog.ui</Form> <Form>WebBrowser/Download/DownloadItem.ui</Form> <Form>WebBrowser/Download/DownloadManager.ui</Form>