Sun, 31 Dec 2017 16:52:09 +0100
Updated copyright for 2018.
# -*- coding: utf-8 -*- # Copyright (c) 2012 - 2018 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a tree widget for the AdBlock configuration dialog. """ from __future__ import unicode_literals from PyQt5.QtCore import Qt from PyQt5.QtGui import QFont, QColor from PyQt5.QtWidgets import QAbstractItemView, QTreeWidgetItem, QInputDialog, \ QLineEdit, QMenu, QApplication from E5Gui.E5TreeWidget import E5TreeWidget class AdBlockTreeWidget(E5TreeWidget): """ Class implementing a tree widget for the AdBlock configuration dialog. """ def __init__(self, subscription, parent=None): """ Constructor @param subscription reference to the subscription @type AdBlockSubscription @param parent reference to the parent widget @type QWidget """ super(AdBlockTreeWidget, self).__init__(parent) self.__subscription = subscription self.__topItem = None self.__ruleToBeSelected = "" self.__itemChangingBlock = False self.setContextMenuPolicy(Qt.CustomContextMenu) self.setDefaultItemShowMode(E5TreeWidget.ItemsExpanded) self.setHeaderHidden(True) self.setAlternatingRowColors(True) self.customContextMenuRequested.connect(self.__contextMenuRequested) self.itemChanged.connect(self.__itemChanged) self.__subscription.changed.connect(self.__subscriptionChanged) self.__subscription.rulesChanged.connect(self.__subscriptionChanged) def subscription(self): """ Public method to get a reference to the subscription. @return reference to the subscription @rtype AdBlockSubscription """ return self.__subscription def showRule(self, rule): """ Public method to highlight the given rule. @param rule AdBlock rule to be shown @type AdBlockRule """ if not bool(self.__topItem) and bool(rule): self.__ruleToBeSelected = rule.filter() elif self.__ruleToBeSelected: items = self.findItems(self.__ruleToBeSelected, Qt.MatchRecursive) if items: item = items[0] self.setCurrentItem(item) self.scrollToItem(item, QAbstractItemView.PositionAtCenter) self.__ruleToBeSelected = "" def refresh(self): """ Public method to refresh the tree. """ QApplication.setOverrideCursor(Qt.WaitCursor) self.__itemChangingBlock = True self.clear() boldFont = QFont() boldFont.setBold(True) self.__topItem = QTreeWidgetItem(self) self.__topItem.setText(0, self.__subscription.title()) self.__topItem.setFont(0, boldFont) self.addTopLevelItem(self.__topItem) allRules = self.__subscription.allRules() index = 0 for rule in allRules: item = QTreeWidgetItem(self.__topItem) item.setText(0, rule.filter()) item.setData(0, Qt.UserRole, index) if self.__subscription.canEditRules(): item.setFlags(item.flags() | Qt.ItemIsEditable) self.__adjustItemFeatures(item, rule) index += 1 self.expandAll() self.showRule(None) self.__itemChangingBlock = False QApplication.restoreOverrideCursor() QApplication.processEvents() def addRule(self, filterRule=""): """ Public slot to add a new rule. @param filterRule filter to be added @type str """ if not self.__subscription.canEditRules(): return if not filterRule: filterRule, ok = QInputDialog.getText( self, self.tr("Add Custom Rule"), self.tr("Write your rule here:"), QLineEdit.Normal) if not ok or filterRule == "": return from .AdBlockRule import AdBlockRule rule = AdBlockRule(filterRule, self.__subscription) self.__subscription.addRule(rule) def removeRule(self): """ Public slot to remove the current rule. """ item = self.currentItem() if item is None or \ not self.__subscription.canEditRules() or \ item == self.__topItem: return offset = item.data(0, Qt.UserRole) self.__subscription.removeRule(offset) self.deleteItem(item) def __contextMenuRequested(self, pos): """ Private slot to show the context menu. @param pos position for the menu @type QPoint """ if not self.__subscription.canEditRules(): return item = self.itemAt(pos) if item is None: return menu = QMenu() menu.addAction(self.tr("Add Rule"), self.addRule) menu.addSeparator() act = menu.addAction(self.tr("Remove Rule"), self.removeRule) if item.parent() is None: act.setDisabled(True) menu.exec_(self.viewport().mapToGlobal(pos)) def __itemChanged(self, itm): """ Private slot to handle the change of an item. @param itm changed item @type QTreeWidgetItem """ if itm is None or self.__itemChangingBlock: return self.__itemChangingBlock = True offset = itm.data(0, Qt.UserRole) oldRule = self.__subscription.rule(offset) if itm.checkState(0) == Qt.Unchecked and oldRule.isEnabled(): # Disable rule rule = self.__subscription.setRuleEnabled(offset, False) self.__adjustItemFeatures(itm, rule) elif itm.checkState(0) == Qt.Checked and not oldRule.isEnabled(): # Enable rule rule = self.__subscription.setRuleEnabled(offset, True) self.__adjustItemFeatures(itm, rule) elif self.__subscription.canEditRules(): from .AdBlockRule import AdBlockRule # Custom rule has been changed rule = self.__subscription.replaceRule( AdBlockRule(itm.text(0), self.__subscription), offset) self.__adjustItemFeatures(itm, rule) self.__itemChangingBlock = False def __copyFilter(self): """ Private slot to copy the current filter to the clipboard. """ item = self.currentItem() if item is not None: QApplication.clipboard().setText(item.text(0)) def __subscriptionChanged(self): """ Private slot handling a subscription change. """ self.refresh() self.__itemChangingBlock = True self.__topItem.setText( 0, self.tr("{0} (recently updated)").format( self.__subscription.title())) self.__itemChangingBlock = False def __adjustItemFeatures(self, itm, rule): """ Private method to adjust an item. @param itm item to be adjusted @type QTreeWidgetItem @param rule rule for the adjustment @type AdBlockRule """ if not rule.isEnabled(): font = QFont() font.setItalic(True) itm.setForeground(0, QColor(Qt.gray)) if not rule.isComment() and not rule.isHeader(): itm.setFlags(itm.flags() | Qt.ItemIsUserCheckable) itm.setCheckState(0, Qt.Unchecked) itm.setFont(0, font) return itm.setFlags(itm.flags() | Qt.ItemIsUserCheckable) itm.setCheckState(0, Qt.Checked) if rule.isCSSRule(): itm.setForeground(0, QColor(Qt.darkBlue)) itm.setFont(0, QFont()) elif rule.isException(): itm.setForeground(0, QColor(Qt.darkGreen)) itm.setFont(0, QFont()) else: itm.setForeground(0, QColor()) itm.setFont(0, QFont()) def keyPressEvent(self, evt): """ Protected method handling key presses. @param evt key press event @type QKeyEvent """ if evt.key() == Qt.Key_C and \ evt.modifiers() & Qt.ControlModifier: self.__copyFilter() elif evt.key() == Qt.Key_Delete: self.removeRule() else: super(AdBlockTreeWidget, self).keyPressEvent(evt)