Falkon Develop
Cross-platform Qt-based web browser
adblocktreewidget.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "adblocktreewidget.h"
19#include "adblocksubscription.h"
20
21#include <QMenu>
22#include <QKeyEvent>
23#include <QClipboard>
24#include <QApplication>
25#include <QInputDialog>
26
28 : TreeWidget(parent)
29 , m_subscription(subscription)
30 , m_topItem(nullptr)
31 , m_itemChangingBlock(false)
32{
33 setContextMenuPolicy(Qt::CustomContextMenu);
35 setHeaderHidden(true);
36 setAlternatingRowColors(true);
37 setLayoutDirection(Qt::LeftToRight);
38
39 connect(this, &QWidget::customContextMenuRequested, this, &AdBlockTreeWidget::contextMenuRequested);
40 connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(itemChanged(QTreeWidgetItem*)));
41 connect(m_subscription, &AdBlockSubscription::subscriptionUpdated, this, &AdBlockTreeWidget::subscriptionUpdated);
42 connect(m_subscription, &AdBlockSubscription::subscriptionError, this, &AdBlockTreeWidget::subscriptionError);
43}
44
46{
47 return m_subscription;
48}
49
51{
52 if (!m_topItem && rule) {
53 m_ruleToBeSelected = rule->filter();
54 }
55 else if (!m_ruleToBeSelected.isEmpty()) {
56 QList<QTreeWidgetItem*> items = findItems(m_ruleToBeSelected, Qt::MatchRecursive);
57 if (!items.isEmpty()) {
58 QTreeWidgetItem* item = items.at(0);
59
60 setCurrentItem(item);
61 scrollToItem(item, QAbstractItemView::PositionAtCenter);
62 }
63
64 m_ruleToBeSelected.clear();
65 }
66}
67
68void AdBlockTreeWidget::contextMenuRequested(const QPoint &pos)
69{
70 if (!m_subscription->canEditRules()) {
71 return;
72 }
73
74 QTreeWidgetItem* item = itemAt(pos);
75 if (!item) {
76 return;
77 }
78
79 QMenu menu;
80 menu.addAction(tr("Add Rule"), this, &AdBlockTreeWidget::addRule);
81 menu.addSeparator();
82 QAction* deleteAction = menu.addAction(tr("Remove Rule"), this, &AdBlockTreeWidget::removeRule);
83
84 if (!item->parent()) {
85 deleteAction->setDisabled(true);
86 }
87
88 menu.exec(viewport()->mapToGlobal(pos));
89}
90
91void AdBlockTreeWidget::itemChanged(QTreeWidgetItem* item)
92{
93 if (!item || m_itemChangingBlock) {
94 return;
95 }
96
97 m_itemChangingBlock = true;
98
99 int offset = item->data(0, Qt::UserRole + 10).toInt();
100 const AdBlockRule* oldRule = m_subscription->rule(offset);
101
102 if (item->checkState(0) == Qt::Unchecked && oldRule->isEnabled()) {
103 // Disable rule
104 const AdBlockRule* rule = m_subscription->disableRule(offset);
105
106 adjustItemFeatures(item, rule);
107 }
108 else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) {
109 // Enable rule
110 const AdBlockRule* rule = m_subscription->enableRule(offset);
111
112 adjustItemFeatures(item, rule);
113 }
114 else if (m_subscription->canEditRules()) {
115 // Custom rule has been changed
116 auto* newRule = new AdBlockRule(item->text(0), m_subscription);
117 const AdBlockRule* rule = m_subscription->replaceRule(newRule, offset);
118
119 adjustItemFeatures(item, rule);
120 }
121
122 m_itemChangingBlock = false;
123}
124
125void AdBlockTreeWidget::copyFilter()
126{
127 QTreeWidgetItem* item = currentItem();
128 if (!item) {
129 return;
130 }
131
132 QApplication::clipboard()->setText(item->text(0));
133}
134
136{
137 if (!m_subscription->canEditRules()) {
138 return;
139 }
140
141 QString newRule = QInputDialog::getText(this, tr("Add Custom Rule"), tr("Please write your rule here:"));
142 if (newRule.isEmpty()) {
143 return;
144 }
145
146 auto* rule = new AdBlockRule(newRule, m_subscription);
147 int offset = m_subscription->addRule(rule);
148
149 auto* item = new QTreeWidgetItem();
150 item->setText(0, newRule);
151 item->setData(0, Qt::UserRole + 10, offset);
152 item->setFlags(item->flags() | Qt::ItemIsEditable);
153
154 m_itemChangingBlock = true;
155 m_topItem->addChild(item);
156 m_itemChangingBlock = false;
157
158 adjustItemFeatures(item, rule);
159}
160
162{
163 QTreeWidgetItem* item = currentItem();
164 if (!item || !m_subscription->canEditRules() || item == m_topItem) {
165 return;
166 }
167
168 int offset = item->data(0, Qt::UserRole + 10).toInt();
169
170 m_subscription->removeRule(offset);
171 deleteItem(item);
172}
173
174void AdBlockTreeWidget::subscriptionUpdated()
175{
176 refresh();
177
178 m_itemChangingBlock = true;
179 m_topItem->setText(0, tr("%1 (recently updated)").arg(m_subscription->title()));
180 m_itemChangingBlock = false;
181}
182
183void AdBlockTreeWidget::subscriptionError(const QString &message)
184{
185 refresh();
186
187 m_itemChangingBlock = true;
188 m_topItem->setText(0, tr("%1 (Error: %2)").arg(m_subscription->title(), message));
189 m_itemChangingBlock = false;
190}
191
192void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule)
193{
194 if (!rule->isEnabled()) {
195 item->setForeground(0, QColor(Qt::gray));
196
197 if (!rule->isComment()) {
198 QFont f = font();
199 f.setItalic(true);
200 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
201 item->setCheckState(0, Qt::Unchecked);
202 item->setFont(0, f);
203 }
204
205 return;
206 }
207
208 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
209 item->setCheckState(0, Qt::Checked);
210 item->setForeground(0, palette().windowText());
211 item->setFont(0, font());
212
213 if (rule->isUnsupportedRule()) {
214 item->setForeground(0, QColor(Qt::gray));
215 item->setFont(0, QFont());
216 } else if (rule->isException()) {
217 item->setForeground(0, QColor(Qt::darkGreen));
218 item->setFont(0, QFont());
219 }
220 else if (rule->isCssRule()) {
221 item->setForeground(0, QColor(Qt::darkBlue));
222 item->setFont(0, QFont());
223 }
224}
225
226void AdBlockTreeWidget::keyPressEvent(QKeyEvent* event)
227{
228 if (event->key() == Qt::Key_C && event->modifiers() & Qt::ControlModifier) {
229 copyFilter();
230 }
231
232 if (event->key() == Qt::Key_Delete) {
233 removeRule();
234 }
235
236 TreeWidget::keyPressEvent(event);
237}
238
240{
241 m_itemChangingBlock = true;
242 clear();
243
244 QFont boldFont;
245 boldFont.setBold(true);
246
247 m_topItem = new QTreeWidgetItem(this);
248 m_topItem->setText(0, m_subscription->title());
249 m_topItem->setFont(0, boldFont);
250 m_topItem->setExpanded(true);
251 addTopLevelItem(m_topItem);
252
253 const QVector<AdBlockRule*> &allRules = m_subscription->allRules();
254
255 int index = 0;
256 for (const AdBlockRule* rule : allRules) {
257 auto* item = new QTreeWidgetItem(m_topItem);
258 item->setText(0, rule->filter());
259 item->setData(0, Qt::UserRole + 10, index);
260
261 if (m_subscription->canEditRules()) {
262 item->setFlags(item->flags() | Qt::ItemIsEditable);
263 }
264
265 adjustItemFeatures(item, rule);
266 ++index;
267 }
268
269 showRule(nullptr);
270 m_itemChangingBlock = false;
271}
QString filter() const
bool isEnabled() const
bool isException() const
bool isUnsupportedRule() const
bool isCssRule() const
bool isComment() const
virtual const AdBlockRule * replaceRule(AdBlockRule *rule, int offset)
virtual bool canEditRules() const
const AdBlockRule * rule(int offset) const
virtual int addRule(AdBlockRule *rule)
void subscriptionError(const QString &message)
const AdBlockRule * disableRule(int offset)
virtual bool removeRule(int offset)
const AdBlockRule * enableRule(int offset)
QVector< AdBlockRule * > allRules() const
void showRule(const AdBlockRule *rule)
AdBlockTreeWidget(AdBlockSubscription *subscription, QWidget *parent=nullptr)
AdBlockSubscription * subscription() const
void addTopLevelItem(QTreeWidgetItem *item)
Definition: treewidget.cpp:41
void setDefaultItemShowMode(ItemShowMode mode)
Definition: treewidget.h:32
void clear()
Definition: treewidget.cpp:30
void deleteItem(QTreeWidgetItem *item)
Definition: treewidget.cpp:197
@ ItemsExpanded
Definition: treewidget.h:30