src/eric7/WebBrowser/AdBlock/AdBlockTreeWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
8 """ 8 """
9 9
10 from PyQt6.QtCore import Qt 10 from PyQt6.QtCore import Qt
11 from PyQt6.QtGui import QFont, QColor 11 from PyQt6.QtGui import QFont, QColor
12 from PyQt6.QtWidgets import ( 12 from PyQt6.QtWidgets import (
13 QAbstractItemView, QTreeWidgetItem, QInputDialog, QLineEdit, QMenu, 13 QAbstractItemView,
14 QApplication 14 QTreeWidgetItem,
15 QInputDialog,
16 QLineEdit,
17 QMenu,
18 QApplication,
15 ) 19 )
16 20
17 from EricWidgets.EricTreeWidget import EricTreeWidget, EricTreeWidgetItemsState 21 from EricWidgets.EricTreeWidget import EricTreeWidget, EricTreeWidgetItemsState
18 from EricGui.EricOverrideCursor import EricOverrideCursor 22 from EricGui.EricOverrideCursor import EricOverrideCursor
19 from EricWidgets.EricApplication import ericApp 23 from EricWidgets.EricApplication import ericApp
21 25
22 class AdBlockTreeWidget(EricTreeWidget): 26 class AdBlockTreeWidget(EricTreeWidget):
23 """ 27 """
24 Class implementing a tree widget for the AdBlock configuration dialog. 28 Class implementing a tree widget for the AdBlock configuration dialog.
25 """ 29 """
30
26 def __init__(self, subscription, parent=None): 31 def __init__(self, subscription, parent=None):
27 """ 32 """
28 Constructor 33 Constructor
29 34
30 @param subscription reference to the subscription 35 @param subscription reference to the subscription
31 @type AdBlockSubscription 36 @type AdBlockSubscription
32 @param parent reference to the parent widget 37 @param parent reference to the parent widget
33 @type QWidget 38 @type QWidget
34 """ 39 """
35 super().__init__(parent) 40 super().__init__(parent)
36 41
37 self.__subscription = subscription 42 self.__subscription = subscription
38 self.__topItem = None 43 self.__topItem = None
39 self.__ruleToBeSelected = "" 44 self.__ruleToBeSelected = ""
40 self.__itemChangingBlock = False 45 self.__itemChangingBlock = False
41 46
42 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) 47 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
43 self.setDefaultItemShowMode(EricTreeWidgetItemsState.EXPANDED) 48 self.setDefaultItemShowMode(EricTreeWidgetItemsState.EXPANDED)
44 self.setHeaderHidden(True) 49 self.setHeaderHidden(True)
45 self.setAlternatingRowColors(True) 50 self.setAlternatingRowColors(True)
46 51
47 self.__darkMode = ericApp().usesDarkPalette() 52 self.__darkMode = ericApp().usesDarkPalette()
48 53
49 self.customContextMenuRequested.connect(self.__contextMenuRequested) 54 self.customContextMenuRequested.connect(self.__contextMenuRequested)
50 self.itemChanged.connect(self.__itemChanged) 55 self.itemChanged.connect(self.__itemChanged)
51 self.__subscription.changed.connect(self.__subscriptionChanged) 56 self.__subscription.changed.connect(self.__subscriptionChanged)
52 self.__subscription.rulesChanged.connect(self.__subscriptionChanged) 57 self.__subscription.rulesChanged.connect(self.__subscriptionChanged)
53 58
54 def subscription(self): 59 def subscription(self):
55 """ 60 """
56 Public method to get a reference to the subscription. 61 Public method to get a reference to the subscription.
57 62
58 @return reference to the subscription 63 @return reference to the subscription
59 @rtype AdBlockSubscription 64 @rtype AdBlockSubscription
60 """ 65 """
61 return self.__subscription 66 return self.__subscription
62 67
63 def showRule(self, rule): 68 def showRule(self, rule):
64 """ 69 """
65 Public method to highlight the given rule. 70 Public method to highlight the given rule.
66 71
67 @param rule AdBlock rule to be shown 72 @param rule AdBlock rule to be shown
68 @type AdBlockRule 73 @type AdBlockRule
69 """ 74 """
70 if not bool(self.__topItem) and bool(rule): 75 if not bool(self.__topItem) and bool(rule):
71 self.__ruleToBeSelected = rule.filter() 76 self.__ruleToBeSelected = rule.filter()
72 elif self.__ruleToBeSelected: 77 elif self.__ruleToBeSelected:
73 items = self.findItems( 78 items = self.findItems(self.__ruleToBeSelected, Qt.MatchFlag.MatchRecursive)
74 self.__ruleToBeSelected, Qt.MatchFlag.MatchRecursive)
75 if items: 79 if items:
76 item = items[0] 80 item = items[0]
77 self.setCurrentItem(item) 81 self.setCurrentItem(item)
78 self.scrollToItem( 82 self.scrollToItem(item, QAbstractItemView.ScrollHint.PositionAtCenter)
79 item, QAbstractItemView.ScrollHint.PositionAtCenter) 83
80
81 self.__ruleToBeSelected = "" 84 self.__ruleToBeSelected = ""
82 85
83 def refresh(self): 86 def refresh(self):
84 """ 87 """
85 Public method to refresh the tree. 88 Public method to refresh the tree.
86 """ 89 """
87 with EricOverrideCursor(): 90 with EricOverrideCursor():
88 self.__itemChangingBlock = True 91 self.__itemChangingBlock = True
89 self.clear() 92 self.clear()
90 93
91 boldFont = QFont() 94 boldFont = QFont()
92 boldFont.setBold(True) 95 boldFont.setBold(True)
93 96
94 self.__topItem = QTreeWidgetItem(self) 97 self.__topItem = QTreeWidgetItem(self)
95 self.__topItem.setText(0, self.__subscription.title()) 98 self.__topItem.setText(0, self.__subscription.title())
96 self.__topItem.setFont(0, boldFont) 99 self.__topItem.setFont(0, boldFont)
97 self.addTopLevelItem(self.__topItem) 100 self.addTopLevelItem(self.__topItem)
98 101
99 allRules = self.__subscription.allRules() 102 allRules = self.__subscription.allRules()
100 103
101 for index, rule in enumerate(allRules): 104 for index, rule in enumerate(allRules):
102 item = QTreeWidgetItem(self.__topItem) 105 item = QTreeWidgetItem(self.__topItem)
103 item.setText(0, rule.filter()) 106 item.setText(0, rule.filter())
104 item.setData(0, Qt.ItemDataRole.UserRole, index) 107 item.setData(0, Qt.ItemDataRole.UserRole, index)
105 if self.__subscription.canEditRules(): 108 if self.__subscription.canEditRules():
106 item.setFlags(item.flags() | Qt.ItemFlag.ItemIsEditable) 109 item.setFlags(item.flags() | Qt.ItemFlag.ItemIsEditable)
107 self.__adjustItemFeatures(item, rule) 110 self.__adjustItemFeatures(item, rule)
108 111
109 self.expandAll() 112 self.expandAll()
110 self.showRule(None) 113 self.showRule(None)
111 self.__itemChangingBlock = False 114 self.__itemChangingBlock = False
112 115
113 def addRule(self, filterRule=""): 116 def addRule(self, filterRule=""):
114 """ 117 """
115 Public slot to add a new rule. 118 Public slot to add a new rule.
116 119
117 @param filterRule filter to be added 120 @param filterRule filter to be added
118 @type str 121 @type str
119 """ 122 """
120 if not self.__subscription.canEditRules(): 123 if not self.__subscription.canEditRules():
121 return 124 return
122 125
123 if not filterRule: 126 if not filterRule:
124 filterRule, ok = QInputDialog.getText( 127 filterRule, ok = QInputDialog.getText(
125 self, 128 self,
126 self.tr("Add Custom Rule"), 129 self.tr("Add Custom Rule"),
127 self.tr("Write your rule here:"), 130 self.tr("Write your rule here:"),
128 QLineEdit.EchoMode.Normal) 131 QLineEdit.EchoMode.Normal,
132 )
129 if not ok or filterRule == "": 133 if not ok or filterRule == "":
130 return 134 return
131 135
132 from .AdBlockRule import AdBlockRule 136 from .AdBlockRule import AdBlockRule
137
133 rule = AdBlockRule(filterRule, self.__subscription) 138 rule = AdBlockRule(filterRule, self.__subscription)
134 self.__subscription.addRule(rule) 139 self.__subscription.addRule(rule)
135 140
136 def removeRule(self): 141 def removeRule(self):
137 """ 142 """
138 Public slot to remove the current rule. 143 Public slot to remove the current rule.
139 """ 144 """
140 item = self.currentItem() 145 item = self.currentItem()
141 if ( 146 if (
142 item is None or 147 item is None
143 not self.__subscription.canEditRules() or 148 or not self.__subscription.canEditRules()
144 item == self.__topItem 149 or item == self.__topItem
145 ): 150 ):
146 return 151 return
147 152
148 offset = item.data(0, Qt.ItemDataRole.UserRole) 153 offset = item.data(0, Qt.ItemDataRole.UserRole)
149 self.__subscription.removeRule(offset) 154 self.__subscription.removeRule(offset)
150 self.deleteItem(item) 155 self.deleteItem(item)
151 156
152 def __contextMenuRequested(self, pos): 157 def __contextMenuRequested(self, pos):
153 """ 158 """
154 Private slot to show the context menu. 159 Private slot to show the context menu.
155 160
156 @param pos position for the menu 161 @param pos position for the menu
157 @type QPoint 162 @type QPoint
158 """ 163 """
159 if not self.__subscription.canEditRules(): 164 if not self.__subscription.canEditRules():
160 return 165 return
161 166
162 item = self.itemAt(pos) 167 item = self.itemAt(pos)
163 if item is None: 168 if item is None:
164 return 169 return
165 170
166 menu = QMenu() 171 menu = QMenu()
167 menu.addAction(self.tr("Add Rule"), self.addRule) 172 menu.addAction(self.tr("Add Rule"), self.addRule)
168 menu.addSeparator() 173 menu.addSeparator()
169 act = menu.addAction(self.tr("Remove Rule"), self.removeRule) 174 act = menu.addAction(self.tr("Remove Rule"), self.removeRule)
170 if item.parent() is None: 175 if item.parent() is None:
171 act.setDisabled(True) 176 act.setDisabled(True)
172 177
173 menu.exec(self.viewport().mapToGlobal(pos)) 178 menu.exec(self.viewport().mapToGlobal(pos))
174 179
175 def __itemChanged(self, itm): 180 def __itemChanged(self, itm):
176 """ 181 """
177 Private slot to handle the change of an item. 182 Private slot to handle the change of an item.
178 183
179 @param itm changed item 184 @param itm changed item
180 @type QTreeWidgetItem 185 @type QTreeWidgetItem
181 """ 186 """
182 if itm is None or self.__itemChangingBlock: 187 if itm is None or self.__itemChangingBlock:
183 return 188 return
184 189
185 self.__itemChangingBlock = True 190 self.__itemChangingBlock = True
186 191
187 offset = itm.data(0, Qt.ItemDataRole.UserRole) 192 offset = itm.data(0, Qt.ItemDataRole.UserRole)
188 oldRule = self.__subscription.rule(offset) 193 oldRule = self.__subscription.rule(offset)
189 194
190 if ( 195 if itm.checkState(0) == Qt.CheckState.Unchecked and oldRule.isEnabled():
191 itm.checkState(0) == Qt.CheckState.Unchecked and
192 oldRule.isEnabled()
193 ):
194 # Disable rule 196 # Disable rule
195 rule = self.__subscription.setRuleEnabled(offset, False) 197 rule = self.__subscription.setRuleEnabled(offset, False)
196 self.__adjustItemFeatures(itm, rule) 198 self.__adjustItemFeatures(itm, rule)
197 elif ( 199 elif itm.checkState(0) == Qt.CheckState.Checked and not oldRule.isEnabled():
198 itm.checkState(0) == Qt.CheckState.Checked and
199 not oldRule.isEnabled()
200 ):
201 # Enable rule 200 # Enable rule
202 rule = self.__subscription.setRuleEnabled(offset, True) 201 rule = self.__subscription.setRuleEnabled(offset, True)
203 self.__adjustItemFeatures(itm, rule) 202 self.__adjustItemFeatures(itm, rule)
204 elif self.__subscription.canEditRules(): 203 elif self.__subscription.canEditRules():
205 from .AdBlockRule import AdBlockRule 204 from .AdBlockRule import AdBlockRule
205
206 # Custom rule has been changed 206 # Custom rule has been changed
207 rule = self.__subscription.replaceRule( 207 rule = self.__subscription.replaceRule(
208 AdBlockRule(itm.text(0), self.__subscription), offset) 208 AdBlockRule(itm.text(0), self.__subscription), offset
209 )
209 self.__adjustItemFeatures(itm, rule) 210 self.__adjustItemFeatures(itm, rule)
210 211
211 self.__itemChangingBlock = False 212 self.__itemChangingBlock = False
212 213
213 def __copyFilter(self): 214 def __copyFilter(self):
214 """ 215 """
215 Private slot to copy the current filter to the clipboard. 216 Private slot to copy the current filter to the clipboard.
216 """ 217 """
217 item = self.currentItem() 218 item = self.currentItem()
218 if item is not None: 219 if item is not None:
219 QApplication.clipboard().setText(item.text(0)) 220 QApplication.clipboard().setText(item.text(0))
220 221
221 def __subscriptionChanged(self): 222 def __subscriptionChanged(self):
222 """ 223 """
223 Private slot handling a subscription change. 224 Private slot handling a subscription change.
224 """ 225 """
225 self.refresh() 226 self.refresh()
226 227
227 self.__itemChangingBlock = True 228 self.__itemChangingBlock = True
228 self.__topItem.setText( 229 self.__topItem.setText(
229 0, self.tr("{0} (recently updated)").format( 230 0, self.tr("{0} (recently updated)").format(self.__subscription.title())
230 self.__subscription.title())) 231 )
231 self.__itemChangingBlock = False 232 self.__itemChangingBlock = False
232 233
233 def __adjustItemFeatures(self, itm, rule): 234 def __adjustItemFeatures(self, itm, rule):
234 """ 235 """
235 Private method to adjust an item. 236 Private method to adjust an item.
236 237
237 @param itm item to be adjusted 238 @param itm item to be adjusted
238 @type QTreeWidgetItem 239 @type QTreeWidgetItem
239 @param rule rule for the adjustment 240 @param rule rule for the adjustment
240 @type AdBlockRule 241 @type AdBlockRule
241 """ 242 """
244 font.setItalic(True) 245 font.setItalic(True)
245 if self.__darkMode: 246 if self.__darkMode:
246 itm.setForeground(0, QColor("#a3a3a3")) 247 itm.setForeground(0, QColor("#a3a3a3"))
247 else: 248 else:
248 itm.setForeground(0, QColor(Qt.GlobalColor.gray)) 249 itm.setForeground(0, QColor(Qt.GlobalColor.gray))
249 250
250 if not rule.isComment() and not rule.isHeader(): 251 if not rule.isComment() and not rule.isHeader():
251 itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable) 252 itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable)
252 itm.setCheckState(0, Qt.CheckState.Unchecked) 253 itm.setCheckState(0, Qt.CheckState.Unchecked)
253 itm.setFont(0, font) 254 itm.setFont(0, font)
254 255
255 return 256 return
256 257
257 itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable) 258 itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable)
258 itm.setCheckState(0, Qt.CheckState.Checked) 259 itm.setCheckState(0, Qt.CheckState.Checked)
259 260
260 if rule.isCSSRule(): 261 if rule.isCSSRule():
261 if self.__darkMode: 262 if self.__darkMode:
262 itm.setForeground(0, QColor("#7897d1")) 263 itm.setForeground(0, QColor("#7897d1"))
263 else: 264 else:
264 itm.setForeground(0, QColor(Qt.GlobalColor.darkBlue)) 265 itm.setForeground(0, QColor(Qt.GlobalColor.darkBlue))
273 if self.__darkMode: 274 if self.__darkMode:
274 itm.setForeground(0, QColor("#fefefe")) 275 itm.setForeground(0, QColor("#fefefe"))
275 else: 276 else:
276 itm.setForeground(0, QColor("#000000")) 277 itm.setForeground(0, QColor("#000000"))
277 itm.setFont(0, QFont()) 278 itm.setFont(0, QFont())
278 279
279 def keyPressEvent(self, evt): 280 def keyPressEvent(self, evt):
280 """ 281 """
281 Protected method handling key presses. 282 Protected method handling key presses.
282 283
283 @param evt key press event 284 @param evt key press event
284 @type QKeyEvent 285 @type QKeyEvent
285 """ 286 """
286 if ( 287 if (
287 evt.key() == Qt.Key.Key_C and 288 evt.key() == Qt.Key.Key_C
288 evt.modifiers() & Qt.KeyboardModifier.ControlModifier 289 and evt.modifiers() & Qt.KeyboardModifier.ControlModifier
289 ): 290 ):
290 self.__copyFilter() 291 self.__copyFilter()
291 elif evt.key() == Qt.Key.Key_Delete: 292 elif evt.key() == Qt.Key.Key_Delete:
292 self.removeRule() 293 self.removeRule()
293 else: 294 else:

eric ide

mercurial