Continued porting the web browser. QtWebEngine

Sat, 12 Mar 2016 16:49:36 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 12 Mar 2016 16:49:36 +0100
branch
QtWebEngine
changeset 4845
2d22ff71c005
parent 4840
69ee7965ba27
child 4846
960e5e18894b

Continued porting the web browser.

- added cookies stuff

Preferences/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookieDetailsDialog.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookieDetailsDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookieExceptionsModel.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookieJar.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookieModel.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookiesConfigurationDialog.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookiesConfigurationDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookiesDialog.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookiesDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookiesExceptionsDialog.py file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/CookiesExceptionsDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/CookieJar/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/Network/NetworkManager.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- 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>&lt;b&gt;Configure cookies&lt;/b&gt;</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>&amp;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>&amp;Exceptions...</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>&amp;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>&amp;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>&amp;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>&amp;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 &amp;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&amp;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>&amp;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>&amp;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 &amp;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&amp;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>&amp;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 &amp;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>

eric ide

mercurial