eric7/WebBrowser/AdBlock/AdBlockTreeWidget.py

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

eric ide

mercurial