File indexing completed on 2024-05-12 04:57:51
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "adblocktreewidget.h" 0019 #include "adblocksubscription.h" 0020 0021 #include <QMenu> 0022 #include <QKeyEvent> 0023 #include <QClipboard> 0024 #include <QApplication> 0025 #include <QInputDialog> 0026 0027 AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent) 0028 : TreeWidget(parent) 0029 , m_subscription(subscription) 0030 , m_topItem(nullptr) 0031 , m_itemChangingBlock(false) 0032 { 0033 setContextMenuPolicy(Qt::CustomContextMenu); 0034 setDefaultItemShowMode(TreeWidget::ItemsExpanded); 0035 setHeaderHidden(true); 0036 setAlternatingRowColors(true); 0037 setLayoutDirection(Qt::LeftToRight); 0038 0039 connect(this, &QWidget::customContextMenuRequested, this, &AdBlockTreeWidget::contextMenuRequested); 0040 connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(itemChanged(QTreeWidgetItem*))); 0041 connect(m_subscription, &AdBlockSubscription::subscriptionUpdated, this, &AdBlockTreeWidget::subscriptionUpdated); 0042 connect(m_subscription, &AdBlockSubscription::subscriptionError, this, &AdBlockTreeWidget::subscriptionError); 0043 } 0044 0045 AdBlockSubscription* AdBlockTreeWidget::subscription() const 0046 { 0047 return m_subscription; 0048 } 0049 0050 void AdBlockTreeWidget::showRule(const AdBlockRule* rule) 0051 { 0052 if (!m_topItem && rule) { 0053 m_ruleToBeSelected = rule->filter(); 0054 } 0055 else if (!m_ruleToBeSelected.isEmpty()) { 0056 QList<QTreeWidgetItem*> items = findItems(m_ruleToBeSelected, Qt::MatchRecursive); 0057 if (!items.isEmpty()) { 0058 QTreeWidgetItem* item = items.at(0); 0059 0060 setCurrentItem(item); 0061 scrollToItem(item, QAbstractItemView::PositionAtCenter); 0062 } 0063 0064 m_ruleToBeSelected.clear(); 0065 } 0066 } 0067 0068 void AdBlockTreeWidget::contextMenuRequested(const QPoint &pos) 0069 { 0070 if (!m_subscription->canEditRules()) { 0071 return; 0072 } 0073 0074 QTreeWidgetItem* item = itemAt(pos); 0075 if (!item) { 0076 return; 0077 } 0078 0079 QMenu menu; 0080 menu.addAction(tr("Add Rule"), this, &AdBlockTreeWidget::addRule); 0081 menu.addSeparator(); 0082 QAction* deleteAction = menu.addAction(tr("Remove Rule"), this, &AdBlockTreeWidget::removeRule); 0083 0084 if (!item->parent()) { 0085 deleteAction->setDisabled(true); 0086 } 0087 0088 menu.exec(viewport()->mapToGlobal(pos)); 0089 } 0090 0091 void AdBlockTreeWidget::itemChanged(QTreeWidgetItem* item) 0092 { 0093 if (!item || m_itemChangingBlock) { 0094 return; 0095 } 0096 0097 m_itemChangingBlock = true; 0098 0099 int offset = item->data(0, Qt::UserRole + 10).toInt(); 0100 const AdBlockRule* oldRule = m_subscription->rule(offset); 0101 0102 if (item->checkState(0) == Qt::Unchecked && oldRule->isEnabled()) { 0103 // Disable rule 0104 const AdBlockRule* rule = m_subscription->disableRule(offset); 0105 0106 adjustItemFeatures(item, rule); 0107 } 0108 else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) { 0109 // Enable rule 0110 const AdBlockRule* rule = m_subscription->enableRule(offset); 0111 0112 adjustItemFeatures(item, rule); 0113 } 0114 else if (m_subscription->canEditRules()) { 0115 // Custom rule has been changed 0116 auto* newRule = new AdBlockRule(item->text(0), m_subscription); 0117 const AdBlockRule* rule = m_subscription->replaceRule(newRule, offset); 0118 0119 adjustItemFeatures(item, rule); 0120 } 0121 0122 m_itemChangingBlock = false; 0123 } 0124 0125 void AdBlockTreeWidget::copyFilter() 0126 { 0127 QTreeWidgetItem* item = currentItem(); 0128 if (!item) { 0129 return; 0130 } 0131 0132 QApplication::clipboard()->setText(item->text(0)); 0133 } 0134 0135 void AdBlockTreeWidget::addRule() 0136 { 0137 if (!m_subscription->canEditRules()) { 0138 return; 0139 } 0140 0141 QString newRule = QInputDialog::getText(this, tr("Add Custom Rule"), tr("Please write your rule here:")); 0142 if (newRule.isEmpty()) { 0143 return; 0144 } 0145 0146 auto* rule = new AdBlockRule(newRule, m_subscription); 0147 int offset = m_subscription->addRule(rule); 0148 0149 auto* item = new QTreeWidgetItem(); 0150 item->setText(0, newRule); 0151 item->setData(0, Qt::UserRole + 10, offset); 0152 item->setFlags(item->flags() | Qt::ItemIsEditable); 0153 0154 m_itemChangingBlock = true; 0155 m_topItem->addChild(item); 0156 m_itemChangingBlock = false; 0157 0158 adjustItemFeatures(item, rule); 0159 } 0160 0161 void AdBlockTreeWidget::removeRule() 0162 { 0163 QTreeWidgetItem* item = currentItem(); 0164 if (!item || !m_subscription->canEditRules() || item == m_topItem) { 0165 return; 0166 } 0167 0168 int offset = item->data(0, Qt::UserRole + 10).toInt(); 0169 0170 m_subscription->removeRule(offset); 0171 deleteItem(item); 0172 } 0173 0174 void AdBlockTreeWidget::subscriptionUpdated() 0175 { 0176 refresh(); 0177 0178 m_itemChangingBlock = true; 0179 m_topItem->setText(0, tr("%1 (recently updated)").arg(m_subscription->title())); 0180 m_itemChangingBlock = false; 0181 } 0182 0183 void AdBlockTreeWidget::subscriptionError(const QString &message) 0184 { 0185 refresh(); 0186 0187 m_itemChangingBlock = true; 0188 m_topItem->setText(0, tr("%1 (Error: %2)").arg(m_subscription->title(), message)); 0189 m_itemChangingBlock = false; 0190 } 0191 0192 void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule) 0193 { 0194 if (!rule->isEnabled()) { 0195 item->setForeground(0, QColor(Qt::gray)); 0196 0197 if (!rule->isComment()) { 0198 QFont f = font(); 0199 f.setItalic(true); 0200 item->setFlags(item->flags() | Qt::ItemIsUserCheckable); 0201 item->setCheckState(0, Qt::Unchecked); 0202 item->setFont(0, f); 0203 } 0204 0205 return; 0206 } 0207 0208 item->setFlags(item->flags() | Qt::ItemIsUserCheckable); 0209 item->setCheckState(0, Qt::Checked); 0210 item->setForeground(0, palette().windowText()); 0211 item->setFont(0, font()); 0212 0213 if (rule->isUnsupportedRule()) { 0214 item->setForeground(0, QColor(Qt::gray)); 0215 item->setFont(0, QFont()); 0216 } else if (rule->isException()) { 0217 item->setForeground(0, QColor(Qt::darkGreen)); 0218 item->setFont(0, QFont()); 0219 } 0220 else if (rule->isCssRule()) { 0221 item->setForeground(0, QColor(Qt::darkBlue)); 0222 item->setFont(0, QFont()); 0223 } 0224 } 0225 0226 void AdBlockTreeWidget::keyPressEvent(QKeyEvent* event) 0227 { 0228 if (event->key() == Qt::Key_C && event->modifiers() & Qt::ControlModifier) { 0229 copyFilter(); 0230 } 0231 0232 if (event->key() == Qt::Key_Delete) { 0233 removeRule(); 0234 } 0235 0236 TreeWidget::keyPressEvent(event); 0237 } 0238 0239 void AdBlockTreeWidget::refresh() 0240 { 0241 m_itemChangingBlock = true; 0242 clear(); 0243 0244 QFont boldFont; 0245 boldFont.setBold(true); 0246 0247 m_topItem = new QTreeWidgetItem(this); 0248 m_topItem->setText(0, m_subscription->title()); 0249 m_topItem->setFont(0, boldFont); 0250 m_topItem->setExpanded(true); 0251 addTopLevelItem(m_topItem); 0252 0253 const QVector<AdBlockRule*> &allRules = m_subscription->allRules(); 0254 0255 int index = 0; 0256 for (const AdBlockRule* rule : allRules) { 0257 auto* item = new QTreeWidgetItem(m_topItem); 0258 item->setText(0, rule->filter()); 0259 item->setData(0, Qt::UserRole + 10, index); 0260 0261 if (m_subscription->canEditRules()) { 0262 item->setFlags(item->flags() | Qt::ItemIsEditable); 0263 } 0264 0265 adjustItemFeatures(item, rule); 0266 ++index; 0267 } 0268 0269 showRule(nullptr); 0270 m_itemChangingBlock = false; 0271 }