1 | /*************************************************************************** |
2 | * Copyright (C) 2005-2014 by the Quassel Project * |
3 | * devel@quassel-irc.org * |
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 2 of the License, or * |
8 | * (at your option) version 3. * |
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, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
19 | ***************************************************************************/ |
20 | |
21 | #include "ignorelistsettingspage.h" |
22 | |
23 | #include <QHeaderView> |
24 | #include <QItemSelectionModel> |
25 | #include <QModelIndex> |
26 | #include <QPainter> |
27 | #include <QMessageBox> |
28 | #include <QString> |
29 | #include <QEvent> |
30 | #include <QDebug> |
31 | #include "iconloader.h" |
32 | |
33 | IgnoreListSettingsPage::IgnoreListSettingsPage(QWidget *parent) |
34 | : SettingsPage(tr("IRC" ), tr("Ignore List" ), parent) |
35 | { |
36 | ui.setupUi(this); |
37 | _delegate = new IgnoreListDelegate(ui.ignoreListView); |
38 | ui.newIgnoreRuleButton->setIcon(SmallIcon("list-add" )); |
39 | ui.deleteIgnoreRuleButton->setIcon(SmallIcon("edit-delete" )); |
40 | ui.editIgnoreRuleButton->setIcon(SmallIcon("configure" )); |
41 | |
42 | ui.ignoreListView->setSelectionBehavior(QAbstractItemView::SelectRows); |
43 | ui.ignoreListView->setSelectionMode(QAbstractItemView::SingleSelection); |
44 | ui.ignoreListView->setAlternatingRowColors(true); |
45 | ui.ignoreListView->setTabKeyNavigation(false); |
46 | ui.ignoreListView->setModel(&_ignoreListModel); |
47 | // ui.ignoreListView->setEditTriggers(QAbstractItemView::NoEditTriggers); |
48 | |
49 | // ui.ignoreListView->setSortingEnabled(true); |
50 | ui.ignoreListView->verticalHeader()->hide(); |
51 | ui.ignoreListView->hideColumn(1); |
52 | ui.ignoreListView->resizeColumnToContents(0); |
53 | ui.ignoreListView->horizontalHeader()->setStretchLastSection(true); |
54 | ui.ignoreListView->setItemDelegateForColumn(0, _delegate); |
55 | ui.ignoreListView->viewport()->setAttribute(Qt::WA_Hover); |
56 | ui.ignoreListView->viewport()->setMouseTracking(true); |
57 | |
58 | connect(ui.ignoreListView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); |
59 | connect(ui.newIgnoreRuleButton, SIGNAL(clicked()), this, SLOT(newIgnoreRule())); |
60 | connect(ui.deleteIgnoreRuleButton, SIGNAL(clicked()), this, SLOT(deleteSelectedIgnoreRule())); |
61 | connect(ui.editIgnoreRuleButton, SIGNAL(clicked()), this, SLOT(editSelectedIgnoreRule())); |
62 | connect(&_ignoreListModel, SIGNAL(configChanged(bool)), this, SLOT(setChangedState(bool))); |
63 | connect(&_ignoreListModel, SIGNAL(modelReady(bool)), this, SLOT(enableDialog(bool))); |
64 | |
65 | enableDialog(_ignoreListModel.isReady()); |
66 | } |
67 | |
68 | |
69 | IgnoreListSettingsPage::~IgnoreListSettingsPage() |
70 | { |
71 | delete _delegate; |
72 | } |
73 | |
74 | |
75 | void IgnoreListSettingsPage::load() |
76 | { |
77 | if (_ignoreListModel.configChanged()) |
78 | _ignoreListModel.revert(); |
79 | ui.ignoreListView->selectionModel()->reset(); |
80 | ui.editIgnoreRuleButton->setEnabled(false); |
81 | } |
82 | |
83 | |
84 | void IgnoreListSettingsPage::defaults() |
85 | { |
86 | _ignoreListModel.loadDefaults(); |
87 | } |
88 | |
89 | |
90 | void IgnoreListSettingsPage::save() |
91 | { |
92 | if (_ignoreListModel.configChanged()) { |
93 | _ignoreListModel.commit(); |
94 | } |
95 | ui.ignoreListView->selectionModel()->reset(); |
96 | ui.editIgnoreRuleButton->setEnabled(false); |
97 | } |
98 | |
99 | |
100 | void IgnoreListSettingsPage::enableDialog(bool enabled) |
101 | { |
102 | ui.newIgnoreRuleButton->setEnabled(enabled); |
103 | setEnabled(enabled); |
104 | } |
105 | |
106 | |
107 | void IgnoreListSettingsPage::selectionChanged(const QItemSelection &selection, const QItemSelection &) |
108 | { |
109 | bool state = !selection.isEmpty(); |
110 | ui.deleteIgnoreRuleButton->setEnabled(state); |
111 | ui.editIgnoreRuleButton->setEnabled(state); |
112 | } |
113 | |
114 | |
115 | void IgnoreListSettingsPage::deleteSelectedIgnoreRule() |
116 | { |
117 | if (!ui.ignoreListView->selectionModel()->hasSelection()) |
118 | return; |
119 | |
120 | _ignoreListModel.removeIgnoreRule(ui.ignoreListView->selectionModel()->selectedIndexes()[0].row()); |
121 | } |
122 | |
123 | |
124 | void IgnoreListSettingsPage::newIgnoreRule(QString rule) |
125 | { |
126 | IgnoreListManager::IgnoreListItem newItem = IgnoreListManager::IgnoreListItem(); |
127 | newItem.strictness = IgnoreListManager::SoftStrictness; |
128 | newItem.scope = IgnoreListManager::GlobalScope; |
129 | newItem.isRegEx = false; |
130 | newItem.isActive = true; |
131 | |
132 | bool enableOkButton = false; |
133 | if (!rule.isEmpty()) { |
134 | // we're called from contextmenu |
135 | newItem.ignoreRule = rule; |
136 | enableOkButton = true; |
137 | } |
138 | |
139 | IgnoreListEditDlg *dlg = new IgnoreListEditDlg(newItem, this, enableOkButton); |
140 | dlg->enableOkButton(enableOkButton); |
141 | while (dlg->exec() == QDialog::Accepted) { |
142 | if (!_ignoreListModel.newIgnoreRule(dlg->ignoreListItem())) { |
143 | if (QMessageBox::warning(this, |
144 | tr("Rule already exists" ), |
145 | tr("There is already a rule\n\"%1\"\nPlease choose another rule." ) |
146 | .arg(dlg->ignoreListItem().ignoreRule), |
147 | QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) |
148 | == QMessageBox::Cancel) |
149 | break; |
150 | |
151 | IgnoreListManager::IgnoreListItem item = dlg->ignoreListItem(); |
152 | delete dlg; |
153 | dlg = new IgnoreListEditDlg(item, this); |
154 | } |
155 | else { |
156 | break; |
157 | } |
158 | } |
159 | dlg->deleteLater(); |
160 | } |
161 | |
162 | |
163 | void IgnoreListSettingsPage::editSelectedIgnoreRule() |
164 | { |
165 | if (!ui.ignoreListView->selectionModel()->hasSelection()) |
166 | return; |
167 | int row = ui.ignoreListView->selectionModel()->selectedIndexes()[0].row(); |
168 | IgnoreListEditDlg dlg(_ignoreListModel.ignoreListItemAt(row), this); |
169 | dlg.setAttribute(Qt::WA_DeleteOnClose, false); |
170 | if (dlg.exec() == QDialog::Accepted) { |
171 | _ignoreListModel.setIgnoreListItemAt(row, dlg.ignoreListItem()); |
172 | } |
173 | } |
174 | |
175 | |
176 | void IgnoreListSettingsPage::editIgnoreRule(const QString &ignoreRule) |
177 | { |
178 | ui.ignoreListView->selectionModel()->select(_ignoreListModel.indexOf(ignoreRule), QItemSelectionModel::Select); |
179 | if (ui.ignoreListView->selectionModel()->hasSelection()) // && ui.ignoreListView->selectionModel()->selectedIndexes()[0].row() != -1) |
180 | editSelectedIgnoreRule(); |
181 | else |
182 | newIgnoreRule(ignoreRule); |
183 | } |
184 | |
185 | |
186 | /* |
187 | IgnoreListDelegate |
188 | */ |
189 | void IgnoreListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const |
190 | { |
191 | if (index.column() == 0) { |
192 | QStyle *style = QApplication::style(); |
193 | if (option.state & QStyle::State_Selected) |
194 | painter->fillRect(option.rect, option.palette.highlight()); |
195 | |
196 | QStyleOptionButton opts; |
197 | opts.direction = option.direction; |
198 | opts.rect = option.rect; |
199 | opts.rect.moveLeft(option.rect.center().rx()-10); |
200 | opts.state = option.state; |
201 | opts.state |= index.data().toBool() ? QStyle::State_On : QStyle::State_Off; |
202 | style->drawControl(QStyle::CE_CheckBox, &opts, painter); |
203 | } |
204 | else |
205 | QStyledItemDelegate::paint(painter, option, index); |
206 | } |
207 | |
208 | |
209 | // provide interactivity for the checkboxes |
210 | bool IgnoreListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, |
211 | const QStyleOptionViewItem &option, const QModelIndex &index) |
212 | { |
213 | Q_UNUSED(option) |
214 | switch (event->type()) { |
215 | case QEvent::MouseButtonRelease: |
216 | model->setData(index, !index.data().toBool()); |
217 | return true; |
218 | // don't show the default editor for the column |
219 | case QEvent::MouseButtonDblClick: |
220 | return true; |
221 | default: |
222 | return false; |
223 | } |
224 | } |
225 | |
226 | |
227 | /* |
228 | IgnoreListEditDlg |
229 | */ |
230 | IgnoreListEditDlg::IgnoreListEditDlg(const IgnoreListManager::IgnoreListItem &item, QWidget *parent, bool enabled) |
231 | : QDialog(parent), _ignoreListItem(item), _hasChanged(enabled) |
232 | { |
233 | ui.setupUi(this); |
234 | setAttribute(Qt::WA_DeleteOnClose, false); |
235 | setModal(true); |
236 | // FIXME patch out the bugger completely if it's good without it |
237 | ui.isActiveCheckBox->hide(); |
238 | |
239 | // setup buttongroups |
240 | // this could be moved to .ui file with qt4.5 |
241 | _typeButtonGroup.addButton(ui.senderTypeButton, 0); |
242 | _typeButtonGroup.addButton(ui.messageTypeButton, 1); |
243 | _typeButtonGroup.addButton(ui.ctcpTypeButton, 2); |
244 | _strictnessButtonGroup.addButton(ui.dynamicStrictnessButton, 0); |
245 | _strictnessButtonGroup.addButton(ui.permanentStrictnessButton, 1); |
246 | _scopeButtonGroup.addButton(ui.globalScopeButton, 0); |
247 | _scopeButtonGroup.addButton(ui.networkScopeButton, 1); |
248 | _scopeButtonGroup.addButton(ui.channelScopeButton, 2); |
249 | |
250 | ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); |
251 | |
252 | ui.ignoreRuleLineEdit->setText(item.ignoreRule); |
253 | |
254 | if (item.type == IgnoreListManager::MessageIgnore) |
255 | ui.messageTypeButton->setChecked(true); |
256 | else if (item.type == IgnoreListManager::CtcpIgnore) |
257 | ui.ctcpTypeButton->setChecked(true); |
258 | else |
259 | ui.senderTypeButton->setChecked(true); |
260 | |
261 | ui.isRegExCheckBox->setChecked(item.isRegEx); |
262 | ui.isActiveCheckBox->setChecked(item.isActive); |
263 | |
264 | if (item.strictness == IgnoreListManager::HardStrictness) |
265 | ui.permanentStrictnessButton->setChecked(true); |
266 | else |
267 | ui.dynamicStrictnessButton->setChecked(true); |
268 | |
269 | switch (item.scope) { |
270 | case IgnoreListManager::NetworkScope: |
271 | ui.networkScopeButton->setChecked(true); |
272 | ui.scopeRuleTextEdit->setEnabled(true); |
273 | break; |
274 | case IgnoreListManager::ChannelScope: |
275 | ui.channelScopeButton->setChecked(true); |
276 | ui.scopeRuleTextEdit->setEnabled(true); |
277 | break; |
278 | default: |
279 | ui.globalScopeButton->setChecked(true); |
280 | ui.scopeRuleTextEdit->setEnabled(false); |
281 | } |
282 | |
283 | if (item.scope == IgnoreListManager::GlobalScope) |
284 | ui.scopeRuleTextEdit->clear(); |
285 | else |
286 | ui.scopeRuleTextEdit->setPlainText(item.scopeRule); |
287 | |
288 | connect(ui.ignoreRuleLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(widgetHasChanged())); |
289 | connect(ui.scopeRuleTextEdit, SIGNAL(textChanged()), this, SLOT(widgetHasChanged())); |
290 | connect(&_typeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(widgetHasChanged())); |
291 | connect(&_strictnessButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(widgetHasChanged())); |
292 | connect(&_scopeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(widgetHasChanged())); |
293 | connect(ui.isRegExCheckBox, SIGNAL(stateChanged(int)), this, SLOT(widgetHasChanged())); |
294 | connect(ui.isActiveCheckBox, SIGNAL(stateChanged(int)), this, SLOT(widgetHasChanged())); |
295 | |
296 | connect(ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(aboutToAccept())); |
297 | widgetHasChanged(); |
298 | } |
299 | |
300 | |
301 | void IgnoreListEditDlg::widgetHasChanged() |
302 | { |
303 | if (ui.messageTypeButton->isChecked()) |
304 | _clonedIgnoreListItem.type = IgnoreListManager::MessageIgnore; |
305 | else if (ui.ctcpTypeButton->isChecked()) |
306 | _clonedIgnoreListItem.type = IgnoreListManager::CtcpIgnore; |
307 | else |
308 | _clonedIgnoreListItem.type = IgnoreListManager::SenderIgnore; |
309 | |
310 | if (ui.permanentStrictnessButton->isChecked()) |
311 | _clonedIgnoreListItem.strictness = IgnoreListManager::HardStrictness; |
312 | else |
313 | _clonedIgnoreListItem.strictness = IgnoreListManager::SoftStrictness; |
314 | |
315 | if (ui.networkScopeButton->isChecked()) { |
316 | _clonedIgnoreListItem.scope = IgnoreListManager::NetworkScope; |
317 | ui.scopeRuleTextEdit->setEnabled(true); |
318 | } |
319 | else if (ui.channelScopeButton->isChecked()) { |
320 | _clonedIgnoreListItem.scope = IgnoreListManager::ChannelScope; |
321 | ui.scopeRuleTextEdit->setEnabled(true); |
322 | } |
323 | else { |
324 | _clonedIgnoreListItem.scope = IgnoreListManager::GlobalScope; |
325 | ui.scopeRuleTextEdit->setEnabled(false); |
326 | } |
327 | |
328 | if (_clonedIgnoreListItem.scope == IgnoreListManager::GlobalScope) { |
329 | _clonedIgnoreListItem.scopeRule = QString(); |
330 | } |
331 | else { |
332 | QStringList text = ui.scopeRuleTextEdit->toPlainText().split(";" , QString::SkipEmptyParts); |
333 | QStringList::iterator it = text.begin(); |
334 | while (it != text.end()) { |
335 | *it = it->trimmed(); |
336 | ++it; |
337 | } |
338 | |
339 | _clonedIgnoreListItem.scopeRule = text.join("; " ); |
340 | } |
341 | |
342 | _clonedIgnoreListItem.ignoreRule = ui.ignoreRuleLineEdit->text(); |
343 | _clonedIgnoreListItem.isRegEx = ui.isRegExCheckBox->isChecked(); |
344 | _clonedIgnoreListItem.isActive = ui.isActiveCheckBox->isChecked(); |
345 | |
346 | if (!_clonedIgnoreListItem.ignoreRule.isEmpty() && _clonedIgnoreListItem != _ignoreListItem) |
347 | _hasChanged = true; |
348 | else |
349 | _hasChanged = false; |
350 | ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(_hasChanged); |
351 | } |
352 | |
353 | |
354 | void IgnoreListEditDlg::enableOkButton(bool state) |
355 | { |
356 | ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(state); |
357 | } |
358 | |