|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2009 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the cookie exceptions model. |
|
8 """ |
|
9 |
|
10 from PyQt5.QtCore import Qt, QAbstractTableModel, QSize, QModelIndex |
|
11 from PyQt5.QtGui import QFont, QFontMetrics |
|
12 |
|
13 |
|
14 class CookieExceptionsModel(QAbstractTableModel): |
|
15 """ |
|
16 Class implementing the cookie exceptions model. |
|
17 """ |
|
18 def __init__(self, cookieJar, parent=None): |
|
19 """ |
|
20 Constructor |
|
21 |
|
22 @param cookieJar reference to the cookie jar (CookieJar) |
|
23 @param parent reference to the parent object (QObject) |
|
24 """ |
|
25 super().__init__(parent) |
|
26 |
|
27 self.__cookieJar = cookieJar |
|
28 self.__allowedCookies = self.__cookieJar.allowedCookies() |
|
29 self.__blockedCookies = self.__cookieJar.blockedCookies() |
|
30 self.__sessionCookies = self.__cookieJar.allowForSessionCookies() |
|
31 |
|
32 self.__headers = [ |
|
33 self.tr("Website"), |
|
34 self.tr("Status"), |
|
35 ] |
|
36 |
|
37 def headerData(self, section, orientation, role): |
|
38 """ |
|
39 Public method to get header data from the model. |
|
40 |
|
41 @param section section number (integer) |
|
42 @param orientation orientation (Qt.Orientation) |
|
43 @param role role of the data to retrieve (Qt.ItemDataRole) |
|
44 @return requested data |
|
45 """ |
|
46 if role == Qt.ItemDataRole.SizeHintRole: |
|
47 fm = QFontMetrics(QFont()) |
|
48 height = fm.height() + fm.height() // 3 |
|
49 try: |
|
50 width = fm.horizontalAdvance( |
|
51 self.headerData(section, orientation, |
|
52 Qt.ItemDataRole.DisplayRole)) |
|
53 except AttributeError: |
|
54 width = fm.width( |
|
55 self.headerData(section, orientation, |
|
56 Qt.ItemDataRole.DisplayRole)) |
|
57 return QSize(width, height) |
|
58 |
|
59 if ( |
|
60 orientation == Qt.Orientation.Horizontal and |
|
61 role == Qt.ItemDataRole.DisplayRole |
|
62 ): |
|
63 try: |
|
64 return self.__headers[section] |
|
65 except IndexError: |
|
66 return None |
|
67 |
|
68 return QAbstractTableModel.headerData(self, section, orientation, role) |
|
69 |
|
70 def data(self, index, role): |
|
71 """ |
|
72 Public method to get data from the model. |
|
73 |
|
74 @param index index to get data for (QModelIndex) |
|
75 @param role role of the data to retrieve (integer) |
|
76 @return requested data |
|
77 """ |
|
78 if index.row() < 0 or index.row() >= self.rowCount(): |
|
79 return None |
|
80 |
|
81 if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): |
|
82 row = index.row() |
|
83 if row < len(self.__allowedCookies): |
|
84 if index.column() == 0: |
|
85 return self.__allowedCookies[row] |
|
86 elif index.column() == 1: |
|
87 return self.tr("Allow") |
|
88 else: |
|
89 return None |
|
90 |
|
91 row -= len(self.__allowedCookies) |
|
92 if row < len(self.__blockedCookies): |
|
93 if index.column() == 0: |
|
94 return self.__blockedCookies[row] |
|
95 elif index.column() == 1: |
|
96 return self.tr("Block") |
|
97 else: |
|
98 return None |
|
99 |
|
100 row -= len(self.__blockedCookies) |
|
101 if row < len(self.__sessionCookies): |
|
102 if index.column() == 0: |
|
103 return self.__sessionCookies[row] |
|
104 elif index.column() == 1: |
|
105 return self.tr("Allow For Session") |
|
106 else: |
|
107 return None |
|
108 |
|
109 return None |
|
110 |
|
111 return None |
|
112 |
|
113 def columnCount(self, parent=None): |
|
114 """ |
|
115 Public method to get the number of columns of the model. |
|
116 |
|
117 @param parent parent index (QModelIndex) |
|
118 @return number of columns (integer) |
|
119 """ |
|
120 if parent is None: |
|
121 parent = QModelIndex() |
|
122 |
|
123 if parent.isValid(): |
|
124 return 0 |
|
125 else: |
|
126 return len(self.__headers) |
|
127 |
|
128 def rowCount(self, parent=None): |
|
129 """ |
|
130 Public method to get the number of rows of the model. |
|
131 |
|
132 @param parent parent index (QModelIndex) |
|
133 @return number of rows (integer) |
|
134 """ |
|
135 if parent is None: |
|
136 parent = QModelIndex() |
|
137 |
|
138 if parent.isValid() or self.__cookieJar is None: |
|
139 return 0 |
|
140 else: |
|
141 return ( |
|
142 len(self.__allowedCookies) + |
|
143 len(self.__blockedCookies) + |
|
144 len(self.__sessionCookies) |
|
145 ) |
|
146 |
|
147 def removeRows(self, row, count, parent=None): |
|
148 """ |
|
149 Public method to remove entries from the model. |
|
150 |
|
151 @param row start row (integer) |
|
152 @param count number of rows to remove (integer) |
|
153 @param parent parent index (QModelIndex) |
|
154 @return flag indicating success (boolean) |
|
155 """ |
|
156 if parent is None: |
|
157 parent = QModelIndex() |
|
158 |
|
159 if parent.isValid() or self.__cookieJar is None: |
|
160 return False |
|
161 |
|
162 lastRow = row + count - 1 |
|
163 self.beginRemoveRows(parent, row, lastRow) |
|
164 for i in range(lastRow, row - 1, -1): |
|
165 rowToRemove = i |
|
166 |
|
167 if rowToRemove < len(self.__allowedCookies): |
|
168 del self.__allowedCookies[rowToRemove] |
|
169 continue |
|
170 |
|
171 rowToRemove -= len(self.__allowedCookies) |
|
172 if rowToRemove < len(self.__blockedCookies): |
|
173 del self.__blockedCookies[rowToRemove] |
|
174 continue |
|
175 |
|
176 rowToRemove -= len(self.__blockedCookies) |
|
177 if rowToRemove < len(self.__sessionCookies): |
|
178 del self.__sessionCookies[rowToRemove] |
|
179 continue |
|
180 |
|
181 self.__cookieJar.setAllowedCookies(self.__allowedCookies) |
|
182 self.__cookieJar.setBlockedCookies(self.__blockedCookies) |
|
183 self.__cookieJar.setAllowForSessionCookies(self.__sessionCookies) |
|
184 self.endRemoveRows() |
|
185 |
|
186 return True |
|
187 |
|
188 def addRule(self, host, rule): |
|
189 """ |
|
190 Public method to add an exception rule. |
|
191 |
|
192 @param host name of the host to add a rule for (string) |
|
193 @param rule type of rule to add (CookieJar.Allow, CookieJar.Block or |
|
194 CookieJar.AllowForSession) |
|
195 """ |
|
196 if not host: |
|
197 return |
|
198 |
|
199 from .CookieJar import CookieJar |
|
200 |
|
201 if rule == CookieJar.Allow: |
|
202 self.__addHost( |
|
203 host, self.__allowedCookies, self.__blockedCookies, |
|
204 self.__sessionCookies) |
|
205 return |
|
206 elif rule == CookieJar.Block: |
|
207 self.__addHost( |
|
208 host, self.__blockedCookies, self.__allowedCookies, |
|
209 self.__sessionCookies) |
|
210 return |
|
211 elif rule == CookieJar.AllowForSession: |
|
212 self.__addHost( |
|
213 host, self.__sessionCookies, self.__allowedCookies, |
|
214 self.__blockedCookies) |
|
215 return |
|
216 |
|
217 def __addHost(self, host, addList, removeList1, removeList2): |
|
218 """ |
|
219 Private method to add a host to an exception list. |
|
220 |
|
221 @param host name of the host to add (string) |
|
222 @param addList reference to the list to add it to (list of strings) |
|
223 @param removeList1 reference to first list to remove it from |
|
224 (list of strings) |
|
225 @param removeList2 reference to second list to remove it from |
|
226 (list of strings) |
|
227 """ |
|
228 if host not in addList: |
|
229 addList.append(host) |
|
230 if host in removeList1: |
|
231 removeList1.remove(host) |
|
232 if host in removeList2: |
|
233 removeList2.remove(host) |
|
234 |
|
235 # Avoid to have similar rules (with or without leading dot) |
|
236 # e.g. python-projects.org and .python-projects.org |
|
237 otherRule = host[1:] if host.startswith(".") else '.' + host |
|
238 if otherRule in addList: |
|
239 addList.remove(otherRule) |
|
240 if otherRule in removeList1: |
|
241 removeList1.remove(otherRule) |
|
242 if otherRule in removeList2: |
|
243 removeList2.remove(otherRule) |
|
244 |
|
245 self.__cookieJar.setAllowedCookies(self.__allowedCookies) |
|
246 self.__cookieJar.setBlockedCookies(self.__blockedCookies) |
|
247 self.__cookieJar.setAllowForSessionCookies(self.__sessionCookies) |
|
248 |
|
249 self.beginResetModel() |
|
250 self.endResetModel() |