1 /***************************************************************************
2 * Copyright (C) 2005-2020 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
21 #include "ignorelistsettingspage.h"
25 #include <QHeaderView>
26 #include <QItemSelectionModel>
27 #include <QMessageBox>
28 #include <QModelIndex>
32 #include "expressionmatch.h"
36 IgnoreListSettingsPage::IgnoreListSettingsPage(QWidget* parent)
37 : SettingsPage(tr("IRC"), tr("Ignore List"), parent)
40 _delegate = new IgnoreListDelegate(ui.ignoreListView);
41 ui.newIgnoreRuleButton->setIcon(icon::get("list-add"));
42 ui.deleteIgnoreRuleButton->setIcon(icon::get("edit-delete"));
43 ui.editIgnoreRuleButton->setIcon(icon::get("configure"));
45 ui.ignoreListView->setSelectionBehavior(QAbstractItemView::SelectRows);
46 ui.ignoreListView->setSelectionMode(QAbstractItemView::SingleSelection);
47 ui.ignoreListView->setAlternatingRowColors(true);
48 ui.ignoreListView->setTabKeyNavigation(false);
49 ui.ignoreListView->setModel(&_ignoreListModel);
50 // ui.ignoreListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
52 // ui.ignoreListView->setSortingEnabled(true);
53 ui.ignoreListView->verticalHeader()->hide();
54 ui.ignoreListView->hideColumn(1);
55 ui.ignoreListView->resizeColumnToContents(0);
56 ui.ignoreListView->horizontalHeader()->setStretchLastSection(true);
57 ui.ignoreListView->setItemDelegateForColumn(0, _delegate);
58 ui.ignoreListView->viewport()->setAttribute(Qt::WA_Hover);
59 ui.ignoreListView->viewport()->setMouseTracking(true);
61 connect(ui.ignoreListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &IgnoreListSettingsPage::selectionChanged);
62 connect(ui.newIgnoreRuleButton, &QAbstractButton::clicked, this, [this]() { newIgnoreRule(); });
63 connect(ui.deleteIgnoreRuleButton, &QAbstractButton::clicked, this, &IgnoreListSettingsPage::deleteSelectedIgnoreRule);
64 connect(ui.editIgnoreRuleButton, &QAbstractButton::clicked, this, &IgnoreListSettingsPage::editSelectedIgnoreRule);
65 connect(&_ignoreListModel, &IgnoreListModel::configChanged, this, &IgnoreListSettingsPage::setChangedState);
66 connect(&_ignoreListModel, &IgnoreListModel::modelReady, this, &IgnoreListSettingsPage::enableDialog);
68 enableDialog(_ignoreListModel.isReady());
71 IgnoreListSettingsPage::~IgnoreListSettingsPage()
76 void IgnoreListSettingsPage::load()
78 if (_ignoreListModel.hasConfigChanged())
79 _ignoreListModel.revert();
80 ui.ignoreListView->selectionModel()->reset();
81 ui.editIgnoreRuleButton->setEnabled(false);
84 void IgnoreListSettingsPage::defaults()
86 _ignoreListModel.loadDefaults();
89 void IgnoreListSettingsPage::save()
91 if (_ignoreListModel.hasConfigChanged()) {
92 _ignoreListModel.commit();
94 ui.ignoreListView->selectionModel()->reset();
95 ui.editIgnoreRuleButton->setEnabled(false);
98 void IgnoreListSettingsPage::enableDialog(bool enabled)
100 ui.newIgnoreRuleButton->setEnabled(enabled);
104 void IgnoreListSettingsPage::selectionChanged(const QItemSelection& selection, const QItemSelection&)
106 bool state = !selection.isEmpty();
107 ui.deleteIgnoreRuleButton->setEnabled(state);
108 ui.editIgnoreRuleButton->setEnabled(state);
111 void IgnoreListSettingsPage::deleteSelectedIgnoreRule()
113 if (!ui.ignoreListView->selectionModel()->hasSelection())
116 _ignoreListModel.removeIgnoreRule(ui.ignoreListView->selectionModel()->selectedIndexes()[0].row());
119 void IgnoreListSettingsPage::newIgnoreRule(const QString& rule)
121 IgnoreListManager::IgnoreListItem newItem = IgnoreListManager::IgnoreListItem();
122 newItem.setStrictness(IgnoreListManager::SoftStrictness);
123 newItem.setScope(IgnoreListManager::GlobalScope);
124 newItem.setIsRegEx(false);
125 newItem.setIsEnabled(true);
127 bool enableOkButton = false;
128 if (!rule.isEmpty()) {
129 // we're called from contextmenu
130 newItem.setContents(rule);
131 enableOkButton = true;
134 auto* dlg = new IgnoreListEditDlg(newItem, this, enableOkButton);
135 dlg->enableOkButton(enableOkButton);
136 while (dlg->exec() == QDialog::Accepted) {
137 if (!_ignoreListModel.newIgnoreRule(dlg->ignoreListItem())) {
138 if (QMessageBox::warning(this,
139 tr("Rule already exists"),
140 tr("There is already a rule\n\"%1\"\nPlease choose another rule.").arg(dlg->ignoreListItem().contents()),
141 QMessageBox::Ok | QMessageBox::Cancel,
143 == QMessageBox::Cancel)
146 IgnoreListManager::IgnoreListItem item = dlg->ignoreListItem();
148 dlg = new IgnoreListEditDlg(item, this);
157 void IgnoreListSettingsPage::editSelectedIgnoreRule()
159 if (!ui.ignoreListView->selectionModel()->hasSelection())
161 int row = ui.ignoreListView->selectionModel()->selectedIndexes()[0].row();
162 IgnoreListEditDlg dlg(_ignoreListModel.ignoreListItemAt(row), this);
163 dlg.setAttribute(Qt::WA_DeleteOnClose, false);
164 if (dlg.exec() == QDialog::Accepted) {
165 _ignoreListModel.setIgnoreListItemAt(row, dlg.ignoreListItem());
169 void IgnoreListSettingsPage::editIgnoreRule(const QString& ignoreRule)
171 ui.ignoreListView->selectionModel()->select(_ignoreListModel.indexOf(ignoreRule), QItemSelectionModel::Select);
172 if (ui.ignoreListView->selectionModel()->hasSelection()) // && ui.ignoreListView->selectionModel()->selectedIndexes()[0].row() != -1)
173 editSelectedIgnoreRule();
175 newIgnoreRule(ignoreRule);
181 void IgnoreListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
183 if (index.column() == 0) {
184 QStyle* style = QApplication::style();
185 if (option.state & QStyle::State_Selected)
186 painter->fillRect(option.rect, option.palette.highlight());
188 QStyleOptionButton opts;
189 opts.direction = option.direction;
190 opts.rect = option.rect;
191 opts.rect.moveLeft(option.rect.center().rx() - 10);
192 opts.state = option.state;
193 opts.state |= index.data().toBool() ? QStyle::State_On : QStyle::State_Off;
194 style->drawControl(QStyle::CE_CheckBox, &opts, painter);
197 QStyledItemDelegate::paint(painter, option, index);
200 // provide interactivity for the checkboxes
201 bool IgnoreListDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
204 switch (event->type()) {
205 case QEvent::MouseButtonRelease:
206 model->setData(index, !index.data().toBool());
208 // don't show the default editor for the column
209 case QEvent::MouseButtonDblClick:
219 IgnoreListEditDlg::IgnoreListEditDlg(const IgnoreListManager::IgnoreListItem& item, QWidget* parent, bool enabled)
221 , _ignoreListItem(item)
222 , _hasChanged(enabled)
225 setAttribute(Qt::WA_DeleteOnClose, false);
227 // FIXME patch out the bugger completely if it's good without it
228 ui.isActiveCheckBox->hide();
230 // setup buttongroups
231 // this could be moved to .ui file with qt4.5
232 _typeButtonGroup.addButton(ui.senderTypeButton, 0);
233 _typeButtonGroup.addButton(ui.messageTypeButton, 1);
234 _typeButtonGroup.addButton(ui.ctcpTypeButton, 2);
235 _strictnessButtonGroup.addButton(ui.dynamicStrictnessButton, 0);
236 _strictnessButtonGroup.addButton(ui.permanentStrictnessButton, 1);
237 _scopeButtonGroup.addButton(ui.globalScopeButton, 0);
238 _scopeButtonGroup.addButton(ui.networkScopeButton, 1);
239 _scopeButtonGroup.addButton(ui.channelScopeButton, 2);
241 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
243 ui.ignoreRuleLineEdit->setText(item.contents());
245 if (item.type() == IgnoreListManager::MessageIgnore)
246 ui.messageTypeButton->setChecked(true);
247 else if (item.type() == IgnoreListManager::CtcpIgnore)
248 ui.ctcpTypeButton->setChecked(true);
250 ui.senderTypeButton->setChecked(true);
252 ui.isRegExCheckBox->setChecked(item.isRegEx());
253 ui.isActiveCheckBox->setChecked(item.isEnabled());
255 if (item.strictness() == IgnoreListManager::HardStrictness)
256 ui.permanentStrictnessButton->setChecked(true);
258 ui.dynamicStrictnessButton->setChecked(true);
260 switch (item.scope()) {
261 case IgnoreListManager::NetworkScope:
262 ui.networkScopeButton->setChecked(true);
263 ui.scopeRuleTextEdit->setEnabled(true);
265 case IgnoreListManager::ChannelScope:
266 ui.channelScopeButton->setChecked(true);
267 ui.scopeRuleTextEdit->setEnabled(true);
270 ui.globalScopeButton->setChecked(true);
271 ui.scopeRuleTextEdit->setEnabled(false);
274 if (item.scope() == IgnoreListManager::GlobalScope)
275 ui.scopeRuleTextEdit->clear();
277 ui.scopeRuleTextEdit->setPlainText(item.scopeRule());
279 connect(ui.ignoreRuleLineEdit, &QLineEdit::textChanged, this, &IgnoreListEditDlg::widgetHasChanged);
280 connect(ui.scopeRuleTextEdit, &QPlainTextEdit::textChanged, this, &IgnoreListEditDlg::widgetHasChanged);
281 connect(&_typeButtonGroup, selectOverload<int>(&QButtonGroup::buttonClicked), this, &IgnoreListEditDlg::widgetHasChanged);
282 connect(&_strictnessButtonGroup, selectOverload<int>(&QButtonGroup::buttonClicked), this, &IgnoreListEditDlg::widgetHasChanged);
283 connect(&_scopeButtonGroup, selectOverload<int>(&QButtonGroup::buttonClicked), this, &IgnoreListEditDlg::widgetHasChanged);
284 connect(ui.isRegExCheckBox, &QCheckBox::stateChanged, this, &IgnoreListEditDlg::widgetHasChanged);
285 connect(ui.isActiveCheckBox, &QCheckBox::stateChanged, this, &IgnoreListEditDlg::widgetHasChanged);
287 connect(ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &IgnoreListEditDlg::aboutToAccept);
291 void IgnoreListEditDlg::widgetHasChanged()
293 if (ui.messageTypeButton->isChecked())
294 _clonedIgnoreListItem.setType(IgnoreListManager::MessageIgnore);
295 else if (ui.ctcpTypeButton->isChecked())
296 _clonedIgnoreListItem.setType(IgnoreListManager::CtcpIgnore);
298 _clonedIgnoreListItem.setType(IgnoreListManager::SenderIgnore);
300 if (ui.permanentStrictnessButton->isChecked())
301 _clonedIgnoreListItem.setStrictness(IgnoreListManager::HardStrictness);
303 _clonedIgnoreListItem.setStrictness(IgnoreListManager::SoftStrictness);
305 if (ui.networkScopeButton->isChecked()) {
306 _clonedIgnoreListItem.setScope(IgnoreListManager::NetworkScope);
307 ui.scopeRuleTextEdit->setEnabled(true);
309 else if (ui.channelScopeButton->isChecked()) {
310 _clonedIgnoreListItem.setScope(IgnoreListManager::ChannelScope);
311 ui.scopeRuleTextEdit->setEnabled(true);
314 _clonedIgnoreListItem.setScope(IgnoreListManager::GlobalScope);
315 ui.scopeRuleTextEdit->setEnabled(false);
318 if (_clonedIgnoreListItem.scope() == IgnoreListManager::GlobalScope) {
319 _clonedIgnoreListItem.setScopeRule(QString());
322 // Trim the resulting MultiWildcard expression
323 _clonedIgnoreListItem.setScopeRule(ExpressionMatch::trimMultiWildcardWhitespace(ui.scopeRuleTextEdit->toPlainText()));
326 _clonedIgnoreListItem.setContents(ui.ignoreRuleLineEdit->text());
327 _clonedIgnoreListItem.setIsRegEx(ui.isRegExCheckBox->isChecked());
328 _clonedIgnoreListItem.setIsEnabled(ui.isActiveCheckBox->isChecked());
330 if (!_clonedIgnoreListItem.contents().isEmpty() && _clonedIgnoreListItem != _ignoreListItem)
334 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(_hasChanged);
337 void IgnoreListEditDlg::enableOkButton(bool state)
339 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(state);