1 /***************************************************************************
2 * Copyright (C) 2005-2016 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 <QHeaderView>
22 #include <QTableWidget>
25 #include "corehighlightsettingspage.h"
28 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent)
29 : SettingsPage(tr("Interface"), tr("Remote Highlights"), parent)
33 setupRuleTable(ui.highlightTable);
34 setupRuleTable(ui.ignoredTable);
36 ui.highlightNicksComboBox->addItem(tr("All Nicks from Identity"), QVariant(HighlightRuleManager::AllNicks));
37 ui.highlightNicksComboBox->addItem(tr("Current Nick"), QVariant(HighlightRuleManager::CurrentNick));
38 ui.highlightNicksComboBox->addItem(tr("None"), QVariant(HighlightRuleManager::NoNick));
40 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
41 connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
43 connect(ui.highlightAdd, SIGNAL(clicked(bool)), this, SLOT(addNewHighlightRow()));
44 connect(ui.highlightRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedHighlightRows()));
45 connect(ui.highlightImport, SIGNAL(clicked(bool)), this, SLOT(importRules()));
47 connect(ui.ignoredAdd, SIGNAL(clicked(bool)), this, SLOT(addNewIgnoredRow()));
48 connect(ui.ignoredRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedIgnoredRows()));
50 // TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
51 connect(ui.highlightTable,
52 SIGNAL(itemClicked(QTableWidgetItem * )),
54 SLOT(selectHighlightRow(QTableWidgetItem * )));
55 connect(ui.ignoredTable,
56 SIGNAL(itemClicked(QTableWidgetItem * )),
58 SLOT(selectIgnoredRow(QTableWidgetItem * )));
61 connect(ui.highlightNicksComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
62 connect(ui.nicksCaseSensitive, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
64 connect(ui.highlightAdd, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
65 connect(ui.highlightRemove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
67 connect(ui.ignoredAdd, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
68 connect(ui.ignoredRemove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
70 connect(ui.highlightTable,
71 SIGNAL(itemChanged(QTableWidgetItem * )),
73 SLOT(highlightTableChanged(QTableWidgetItem * )));
75 connect(ui.ignoredTable,
76 SIGNAL(itemChanged(QTableWidgetItem * )),
78 SLOT(ignoredTableChanged(QTableWidgetItem * )));
80 connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected()));
83 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
93 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const
95 table->verticalHeader()->hide();
96 table->setShowGrid(false);
98 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip(
99 tr("<b>RegEx</b>: This option determines if the highlight rule should be interpreted as a <b>regular expression</b> or just as a keyword."));
100 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis(
101 tr("<b>RegEx</b>: This option determines if the highlight rule should be interpreted as a <b>regular expression</b> or just as a keyword."));
103 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip(
104 tr("<b>CS</b>: This option determines if the highlight rule should be interpreted <b>case sensitive</b>."));
105 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis(
106 tr("<b>CS</b>: This option determines if the highlight rule should be interpreted <b>case sensitive</b>."));
108 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip(
109 tr("<b>Channel</b>: This regular expression determines for which <b>channels</b> the highlight rule works. Leave blank to match any channel. Put <b>!</b> in the beginning to negate. Case insensitive."));
110 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis(
111 tr("<b>Channel</b>: This regular expression determines for which <b>channels</b> the highlight rule works. Leave blank to match any channel. Put <b>!</b> in the beginning to negate. Case insensitive."));
113 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
114 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
115 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
116 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
117 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
118 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
120 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
121 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
122 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
123 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
124 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
128 void CoreHighlightSettingsPage::clientConnected()
130 connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
133 void CoreHighlightSettingsPage::revert()
138 setChangedState(false);
142 bool CoreHighlightSettingsPage::hasDefaults() const
147 void CoreHighlightSettingsPage::defaults()
149 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
150 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
151 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
152 ui.nicksCaseSensitive->setChecked(false);
153 emptyHighlightTable();
159 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, const QString &name, bool regex, bool cs,
160 const QString &sender, const QString &chanName, bool self)
162 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
164 auto *nameItem = new QTableWidgetItem(name);
166 auto *regexItem = new QTableWidgetItem("");
168 regexItem->setCheckState(Qt::Checked);
170 regexItem->setCheckState(Qt::Unchecked);
171 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
173 auto *csItem = new QTableWidgetItem("");
175 csItem->setCheckState(Qt::Checked);
177 csItem->setCheckState(Qt::Unchecked);
178 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
180 auto *enableItem = new QTableWidgetItem("");
182 enableItem->setCheckState(Qt::Checked);
184 enableItem->setCheckState(Qt::Unchecked);
185 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
187 auto *chanNameItem = new QTableWidgetItem(chanName);
189 auto *senderItem = new QTableWidgetItem(sender);
191 int lastRow = ui.highlightTable->rowCount() - 1;
192 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
193 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
194 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
195 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
196 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
197 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
200 ui.highlightTable->setCurrentItem(nameItem);
202 highlightList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, false, sender, chanName);
205 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, const QString &name, bool regex, bool cs,
206 const QString &sender, const QString &chanName, bool self)
208 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
210 auto *nameItem = new QTableWidgetItem(name);
212 auto *regexItem = new QTableWidgetItem("");
214 regexItem->setCheckState(Qt::Checked);
216 regexItem->setCheckState(Qt::Unchecked);
217 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
219 auto *csItem = new QTableWidgetItem("");
221 csItem->setCheckState(Qt::Checked);
223 csItem->setCheckState(Qt::Unchecked);
224 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
226 auto *enableItem = new QTableWidgetItem("");
228 enableItem->setCheckState(Qt::Checked);
230 enableItem->setCheckState(Qt::Unchecked);
231 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
233 auto *chanNameItem = new QTableWidgetItem(chanName);
235 auto *senderItem = new QTableWidgetItem(sender);
237 int lastRow = ui.ignoredTable->rowCount() - 1;
238 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
239 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
240 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
241 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
242 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
243 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
246 ui.ignoredTable->setCurrentItem(nameItem);
248 ignoredList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, true, sender, chanName);
251 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
253 QList<int> selectedRows;
254 QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
255 for (auto selectedItem : selectedItemList) {
256 selectedRows.append(selectedItem->row());
258 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
260 for (auto row : selectedRows) {
261 if (row != lastRow) {
262 ui.highlightTable->removeRow(row);
263 highlightList.removeAt(row);
269 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
271 QList<int> selectedRows;
272 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
273 for (auto selectedItem : selectedItemList) {
274 selectedRows.append(selectedItem->row());
276 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
278 for (auto row : selectedRows) {
279 if (row != lastRow) {
280 ui.ignoredTable->removeRow(row);
281 ignoredList.removeAt(row);
287 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
289 int row = item->row();
290 bool selected = item->isSelected();
292 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
296 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
298 int row = item->row();
299 bool selected = item->isSelected();
301 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
305 void CoreHighlightSettingsPage::emptyHighlightTable()
307 // ui.highlight and highlightList should have the same size, but just to make sure.
308 if (ui.highlightTable->rowCount() != highlightList.size()) {
309 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
311 while (ui.highlightTable->rowCount()) {
312 ui.highlightTable->removeRow(0);
314 highlightList.clear();
317 void CoreHighlightSettingsPage::emptyIgnoredTable()
319 // ui.highlight and highlightList should have the same size, but just to make sure.
320 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
321 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
323 while (ui.ignoredTable->rowCount()) {
324 ui.ignoredTable->removeRow(0);
329 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
331 if (item->row() + 1 > highlightList.size())
334 auto highlightRule = highlightList.value(item->row());
337 switch (item->column()) {
338 case CoreHighlightSettingsPage::EnableColumn:
339 highlightRule.isEnabled = (item->checkState() == Qt::Checked);
341 case CoreHighlightSettingsPage::NameColumn:
342 if (item->text() == "")
343 item->setText(tr("this shouldn't be empty"));
344 highlightRule.name = item->text();
346 case CoreHighlightSettingsPage::RegExColumn:
347 highlightRule.isRegEx = (item->checkState() == Qt::Checked);
349 case CoreHighlightSettingsPage::CsColumn:
350 highlightRule.isCaseSensitive = (item->checkState() == Qt::Checked);
352 case CoreHighlightSettingsPage::SenderColumn:
353 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
355 highlightRule.sender = item->text();
357 case CoreHighlightSettingsPage::ChanColumn:
358 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
360 highlightRule.chanName = item->text();
363 highlightList[item->row()] = highlightRule;
364 emit widgetHasChanged();
367 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
369 if (item->row() + 1 > ignoredList.size())
372 auto ignoredRule = ignoredList.value(item->row());
375 switch (item->column()) {
376 case CoreHighlightSettingsPage::EnableColumn:
377 ignoredRule.isEnabled = (item->checkState() == Qt::Checked);
379 case CoreHighlightSettingsPage::NameColumn:
380 if (item->text() == "")
381 item->setText(tr("this shouldn't be empty"));
382 ignoredRule.name = item->text();
384 case CoreHighlightSettingsPage::RegExColumn:
385 ignoredRule.isRegEx = (item->checkState() == Qt::Checked);
387 case CoreHighlightSettingsPage::CsColumn:
388 ignoredRule.isCaseSensitive = (item->checkState() == Qt::Checked);
390 case CoreHighlightSettingsPage::SenderColumn:
391 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
393 ignoredRule.sender = item->text();
395 case CoreHighlightSettingsPage::ChanColumn:
396 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
398 ignoredRule.chanName = item->text();
401 ignoredList[item->row()] = ignoredRule;
402 emit widgetHasChanged();
405 void CoreHighlightSettingsPage::load()
407 emptyHighlightTable();
410 auto ruleManager = Client::highlightRuleManager();
412 for (auto &rule : ruleManager->highlightRuleList()) {
413 if (rule.isInverse) {
414 addNewIgnoredRow(rule.isEnabled,
417 rule.isCaseSensitive,
422 addNewHighlightRow(rule.isEnabled, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender,
427 int highlightNickType = ruleManager->highlightNick();
428 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
429 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
431 setChangedState(false);
438 void CoreHighlightSettingsPage::save()
446 auto ruleManager = Client::highlightRuleManager();
447 if (ruleManager == nullptr)
450 auto clonedManager = HighlightRuleManager();
451 clonedManager.fromVariantMap(ruleManager->toVariantMap());
452 clonedManager.clear();
454 for (auto &rule : highlightList) {
455 clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false,
456 rule.sender, rule.chanName);
459 for (auto &rule : ignoredList) {
460 clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true,
461 rule.sender, rule.chanName);
464 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
466 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
467 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
469 ruleManager->requestUpdate(clonedManager.toVariantMap());
470 setChangedState(false);
474 void CoreHighlightSettingsPage::widgetHasChanged()
476 setChangedState(true);
479 void CoreHighlightSettingsPage::importRules() {
480 NotificationSettings notificationSettings;
482 auto clonedManager = HighlightRuleManager();
483 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
485 for (const auto &variant : notificationSettings.highlightList()) {
486 auto highlightRule = variant.toMap();
488 clonedManager.addHighlightRule(
489 highlightRule["Name"].toString(),
490 highlightRule["RegEx"].toBool(),
491 highlightRule["CS"].toBool(),
492 highlightRule["Enable"].toBool(),
495 highlightRule["Channel"].toString()
499 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
500 setChangedState(false);
504 bool CoreHighlightSettingsPage::isSelectable() const {
505 return Client::isConnected() && Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights);