1 /***************************************************************************
2 * Copyright (C) 2005-2018 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 <QMessageBox>
23 #include <QTableWidget>
26 #include "corehighlightsettingspage.h"
29 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent)
30 : SettingsPage(tr("Interface"),
31 // In Monolithic mode, local highlights are replaced by remote highlights
32 Quassel::runMode() == Quassel::Monolithic ?
33 tr("Highlights") : tr("Remote Highlights"),
38 setupRuleTable(ui.highlightTable);
39 setupRuleTable(ui.ignoredTable);
41 ui.highlightNicksComboBox->addItem(tr("All Nicks from Identity"), QVariant(HighlightRuleManager::AllNicks));
42 ui.highlightNicksComboBox->addItem(tr("Current Nick"), QVariant(HighlightRuleManager::CurrentNick));
43 ui.highlightNicksComboBox->addItem(tr("None"), QVariant(HighlightRuleManager::NoNick));
45 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
46 connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
48 connect(ui.highlightAdd, SIGNAL(clicked(bool)), this, SLOT(addNewHighlightRow()));
49 connect(ui.highlightRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedHighlightRows()));
50 connect(ui.highlightImport, SIGNAL(clicked(bool)), this, SLOT(importRules()));
52 connect(ui.ignoredAdd, SIGNAL(clicked(bool)), this, SLOT(addNewIgnoredRow()));
53 connect(ui.ignoredRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedIgnoredRows()));
55 // TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
56 connect(ui.highlightTable,
57 SIGNAL(itemClicked(QTableWidgetItem * )),
59 SLOT(selectHighlightRow(QTableWidgetItem * )));
60 connect(ui.ignoredTable,
61 SIGNAL(itemClicked(QTableWidgetItem * )),
63 SLOT(selectIgnoredRow(QTableWidgetItem * )));
65 // Update the "Case sensitive" checkbox
66 connect(ui.highlightNicksComboBox,
67 SIGNAL(currentIndexChanged(int)),
69 SLOT(highlightNicksChanged(int)));
71 connect(ui.highlightNicksComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
72 connect(ui.nicksCaseSensitive, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
74 connect(ui.highlightAdd, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
75 connect(ui.highlightRemove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
77 connect(ui.ignoredAdd, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
78 connect(ui.ignoredRemove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
80 connect(ui.highlightTable,
81 SIGNAL(itemChanged(QTableWidgetItem * )),
83 SLOT(highlightTableChanged(QTableWidgetItem * )));
85 connect(ui.ignoredTable,
86 SIGNAL(itemChanged(QTableWidgetItem * )),
88 SLOT(ignoredTableChanged(QTableWidgetItem * )));
90 connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected()));
93 ui.coreUnsupportedIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(16));
95 // Set up client/monolithic remote highlights information
96 if (Quassel::runMode() == Quassel::Monolithic) {
97 // We're running in Monolithic mode, local highlights are considered legacy
98 ui.highlightImport->setText(tr("Import Legacy"));
99 ui.highlightImport->setToolTip(tr("Import highlight rules configured in <i>%1</i>.")
100 .arg(tr("Legacy Highlights").replace(" ", " ")));
101 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing
102 // all spaces to be non-breaking
104 // We're running in client/split mode, local highlights are distinguished from remote
105 ui.highlightImport->setText(tr("Import Local"));
106 ui.highlightImport->setToolTip(tr("Import highlight rules configured in <i>%1</i>.")
107 .arg(tr("Local Highlights").replace(" ", " ")));
108 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing
109 // all spaces to be non-breaking
113 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
115 updateCoreSupportStatus(state);
124 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const
126 table->verticalHeader()->hide();
127 table->setShowGrid(false);
129 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setToolTip(
130 tr("Enable/disable this rule"));
131 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setWhatsThis(
132 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->toolTip());
134 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setToolTip(
135 tr("Phrase to match"));
136 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setWhatsThis(
137 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->toolTip());
139 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip(
140 tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
141 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
143 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis(
144 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->toolTip());
146 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip(
147 tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
148 "<i>Channel</i> should be interpreted <b>case sensitive</b>."));
149 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis(
150 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->toolTip());
152 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setToolTip(
153 tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
154 "leave blank to match any nickname.</p>"
155 "<p><i>Example:</i><br />"
156 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
157 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
158 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
159 "<p>If only inverted names are specified, it will match anything except for "
160 "what's specified (implicit wildcard).</p>"
161 "<p><i>Example:</i><br />"
162 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
163 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
164 "any nickname starting with <i>Announce</i></p>"));
165 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setWhatsThis(
166 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->toolTip());
168 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip(
169 tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
170 "match any name.</p>"
171 "<p><i>Example:</i><br />"
172 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
173 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
174 "except for <i>#quasseldroid</i><br />"
175 "<p>If only inverted names are specified, it will match anything except for "
176 "what's specified (implicit wildcard).</p>"
177 "<p><i>Example:</i><br />"
178 "<i>!#quassel*; !#foobar</i><br />"
179 "would match anything except for <i>#foobar</i> or any channel starting with "
180 "<i>#quassel</i></p>"));
181 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis(
182 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->toolTip());
184 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
185 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
186 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
187 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
188 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
189 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
191 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
192 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
193 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
194 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
195 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
199 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
201 // Assume connected state as enforced by the settings page UI
202 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
203 // Either disconnected or core supports highlights, enable highlight configuration and hide
204 // warning. Don't show the warning needlessly when disconnected.
205 ui.highlightsConfigWidget->setEnabled(true);
206 ui.coreUnsupportedWidget->setVisible(false);
208 // Core does not support highlights, show warning and disable highlight configuration
209 ui.highlightsConfigWidget->setEnabled(false);
210 ui.coreUnsupportedWidget->setVisible(true);
214 void CoreHighlightSettingsPage::clientConnected()
216 connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
219 void CoreHighlightSettingsPage::revert()
224 setChangedState(false);
228 bool CoreHighlightSettingsPage::hasDefaults() const
233 void CoreHighlightSettingsPage::defaults()
235 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
236 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
237 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
238 ui.nicksCaseSensitive->setChecked(false);
239 emptyHighlightTable();
245 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, const QString &name, bool regex, bool cs,
246 const QString &sender, const QString &chanName, bool self)
248 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
250 auto *nameItem = new QTableWidgetItem(name);
252 auto *regexItem = new QTableWidgetItem("");
254 regexItem->setCheckState(Qt::Checked);
256 regexItem->setCheckState(Qt::Unchecked);
257 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
259 auto *csItem = new QTableWidgetItem("");
261 csItem->setCheckState(Qt::Checked);
263 csItem->setCheckState(Qt::Unchecked);
264 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
266 auto *enableItem = new QTableWidgetItem("");
268 enableItem->setCheckState(Qt::Checked);
270 enableItem->setCheckState(Qt::Unchecked);
271 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
273 auto *senderItem = new QTableWidgetItem(sender);
275 auto *chanNameItem = new QTableWidgetItem(chanName);
277 enableItem->setToolTip(tr("Enable/disable this rule"));
278 nameItem->setToolTip(tr("Phrase to match"));
279 regexItem->setToolTip(
280 tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
281 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
284 tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
285 "<i>Channel</i> should be interpreted <b>case sensitive</b>."));
286 senderItem->setToolTip(
287 tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
288 "leave blank to match any nickname.</p>"
289 "<p><i>Example:</i><br />"
290 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
291 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
292 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
293 "<p>If only inverted names are specified, it will match anything except for "
294 "what's specified (implicit wildcard).</p>"
295 "<p><i>Example:</i><br />"
296 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
297 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
298 "any nickname starting with <i>Announce</i></p>"));
299 chanNameItem->setToolTip(
300 tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
301 "match any name.</p>"
302 "<p><i>Example:</i><br />"
303 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
304 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
305 "except for <i>#quasseldroid</i><br />"
306 "<p>If only inverted names are specified, it will match anything except for "
307 "what's specified (implicit wildcard).</p>"
308 "<p><i>Example:</i><br />"
309 "<i>!#quassel*; !#foobar</i><br />"
310 "would match anything except for <i>#foobar</i> or any channel starting with "
311 "<i>#quassel</i></p>"));
313 int lastRow = ui.highlightTable->rowCount() - 1;
314 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
315 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
316 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
317 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
318 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
319 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
322 ui.highlightTable->setCurrentItem(nameItem);
324 highlightList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, false, sender, chanName);
327 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, const QString &name, bool regex, bool cs,
328 const QString &sender, const QString &chanName, bool self)
330 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
332 auto *nameItem = new QTableWidgetItem(name);
334 auto *regexItem = new QTableWidgetItem("");
336 regexItem->setCheckState(Qt::Checked);
338 regexItem->setCheckState(Qt::Unchecked);
339 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
341 auto *csItem = new QTableWidgetItem("");
343 csItem->setCheckState(Qt::Checked);
345 csItem->setCheckState(Qt::Unchecked);
346 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
348 auto *enableItem = new QTableWidgetItem("");
350 enableItem->setCheckState(Qt::Checked);
352 enableItem->setCheckState(Qt::Unchecked);
353 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
355 auto *chanNameItem = new QTableWidgetItem(chanName);
357 auto *senderItem = new QTableWidgetItem(sender);
359 enableItem->setToolTip(tr("Enable/disable this rule"));
360 nameItem->setToolTip(tr("Phrase to match"));
361 regexItem->setToolTip(
362 tr("<b>RegEx</b>: This option determines if the highlight rule should be "
363 "interpreted as a <b>regular expression</b> or just as a keyword."));
365 tr("<b>CS</b>: This option determines if the highlight rule should be interpreted "
366 "<b>case sensitive</b>."));
367 senderItem->setToolTip(
368 tr("<b>Sender</b>: This option specifies which sender nicknames match. Leave "
369 "blank to match any nickname."));
370 chanNameItem->setToolTip(
371 tr("<p><b>Channel</b>: Semicolon separated list of channel names.</p>"
372 "<p><i>Example:</i><br />"
373 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
374 "would match on #foobar and any channel starting with <i>#quassel</i> except "
375 "for <i>#quasseldroid</i><br />"
376 "<p>If only inverted names are specified, it will match anything except for "
377 "what's specified (implicit wildcard).</p>"
378 "<p><i>Example:</i><br />"
379 "<i>!#quassel*; !#foobar</i><br />"
380 "would match anything except for #foobar or any channel starting with "
381 "<i>#quassel</i></p>"));
383 int lastRow = ui.ignoredTable->rowCount() - 1;
384 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
385 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
386 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
387 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
388 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
389 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
392 ui.ignoredTable->setCurrentItem(nameItem);
394 ignoredList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, true, sender, chanName);
397 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
399 QList<int> selectedRows;
400 QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
401 for (auto selectedItem : selectedItemList) {
402 selectedRows.append(selectedItem->row());
404 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
406 for (auto row : selectedRows) {
407 if (row != lastRow) {
408 ui.highlightTable->removeRow(row);
409 highlightList.removeAt(row);
415 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
417 QList<int> selectedRows;
418 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
419 for (auto selectedItem : selectedItemList) {
420 selectedRows.append(selectedItem->row());
422 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
424 for (auto row : selectedRows) {
425 if (row != lastRow) {
426 ui.ignoredTable->removeRow(row);
427 ignoredList.removeAt(row);
433 void CoreHighlightSettingsPage::highlightNicksChanged(const int index) {
434 // Only allow toggling "Case sensitive" when a nickname will be highlighted
435 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
436 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
439 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
441 int row = item->row();
442 bool selected = item->isSelected();
444 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
448 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
450 int row = item->row();
451 bool selected = item->isSelected();
453 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
457 void CoreHighlightSettingsPage::emptyHighlightTable()
459 // ui.highlight and highlightList should have the same size, but just to make sure.
460 if (ui.highlightTable->rowCount() != highlightList.size()) {
461 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
463 while (ui.highlightTable->rowCount()) {
464 ui.highlightTable->removeRow(0);
466 highlightList.clear();
469 void CoreHighlightSettingsPage::emptyIgnoredTable()
471 // ui.highlight and highlightList should have the same size, but just to make sure.
472 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
473 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
475 while (ui.ignoredTable->rowCount()) {
476 ui.ignoredTable->removeRow(0);
481 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
483 if (item->row() + 1 > highlightList.size())
486 auto highlightRule = highlightList.value(item->row());
489 switch (item->column()) {
490 case CoreHighlightSettingsPage::EnableColumn:
491 highlightRule.isEnabled = (item->checkState() == Qt::Checked);
493 case CoreHighlightSettingsPage::NameColumn:
494 if (item->text() == "")
495 item->setText(tr("this shouldn't be empty"));
496 highlightRule.name = item->text();
498 case CoreHighlightSettingsPage::RegExColumn:
499 highlightRule.isRegEx = (item->checkState() == Qt::Checked);
501 case CoreHighlightSettingsPage::CsColumn:
502 highlightRule.isCaseSensitive = (item->checkState() == Qt::Checked);
504 case CoreHighlightSettingsPage::SenderColumn:
505 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
507 highlightRule.sender = item->text();
509 case CoreHighlightSettingsPage::ChanColumn:
510 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
512 highlightRule.chanName = item->text();
515 highlightList[item->row()] = highlightRule;
516 emit widgetHasChanged();
519 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
521 if (item->row() + 1 > ignoredList.size())
524 auto ignoredRule = ignoredList.value(item->row());
527 switch (item->column()) {
528 case CoreHighlightSettingsPage::EnableColumn:
529 ignoredRule.isEnabled = (item->checkState() == Qt::Checked);
531 case CoreHighlightSettingsPage::NameColumn:
532 if (item->text() == "")
533 item->setText(tr("this shouldn't be empty"));
534 ignoredRule.name = item->text();
536 case CoreHighlightSettingsPage::RegExColumn:
537 ignoredRule.isRegEx = (item->checkState() == Qt::Checked);
539 case CoreHighlightSettingsPage::CsColumn:
540 ignoredRule.isCaseSensitive = (item->checkState() == Qt::Checked);
542 case CoreHighlightSettingsPage::SenderColumn:
543 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
545 ignoredRule.sender = item->text();
547 case CoreHighlightSettingsPage::ChanColumn:
548 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
550 ignoredRule.chanName = item->text();
553 ignoredList[item->row()] = ignoredRule;
554 emit widgetHasChanged();
557 void CoreHighlightSettingsPage::load()
559 emptyHighlightTable();
562 auto ruleManager = Client::highlightRuleManager();
564 for (auto &rule : ruleManager->highlightRuleList()) {
565 if (rule.isInverse) {
566 addNewIgnoredRow(rule.isEnabled,
569 rule.isCaseSensitive,
574 addNewHighlightRow(rule.isEnabled, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender,
579 int highlightNickType = ruleManager->highlightNick();
580 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
581 // Trigger the initial update of nicksCaseSensitive being enabled or not
582 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
583 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
585 setChangedState(false);
592 void CoreHighlightSettingsPage::save()
600 auto ruleManager = Client::highlightRuleManager();
601 if (ruleManager == nullptr)
604 auto clonedManager = HighlightRuleManager();
605 clonedManager.fromVariantMap(ruleManager->toVariantMap());
606 clonedManager.clear();
608 for (auto &rule : highlightList) {
609 clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false,
610 rule.sender, rule.chanName);
613 for (auto &rule : ignoredList) {
614 clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true,
615 rule.sender, rule.chanName);
618 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
620 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
621 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
623 ruleManager->requestUpdate(clonedManager.toVariantMap());
624 setChangedState(false);
628 void CoreHighlightSettingsPage::widgetHasChanged()
630 setChangedState(true);
633 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
635 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
636 // spaces to non-breaking
637 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
639 const QString remoteHighlightsMsgText =
640 QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>"
641 ).arg(tr("Your Quassel core is too old to support remote highlights"),
642 tr("You need a Quassel core v0.13.0 or newer to configure remote "
644 tr("You can still configure highlights for this device only in "
645 "<i>%1</i>.").arg(localHighlightsName));
647 QMessageBox::warning(this,
648 tr("Remote Highlights unsupported"),
649 remoteHighlightsMsgText);
652 void CoreHighlightSettingsPage::importRules() {
653 NotificationSettings notificationSettings;
655 const auto localHighlightList = notificationSettings.highlightList();
657 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
658 // forcing all spaces to non-breaking
659 QString localHighlightsName;
660 if (Quassel::runMode() == Quassel::Monolithic) {
661 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
663 localHighlightsName = tr("Local Highlights").replace(" ", " ");
666 if (localHighlightList.count() == 0) {
667 // No highlight rules exist to import, do nothing
668 QMessageBox::information(this,
669 tr("No highlights to import"),
670 tr("No highlight rules in <i>%1</i>."
671 ).arg(localHighlightsName));
675 int ret = QMessageBox::question(this,
676 tr("Import highlights?"),
677 tr("Import all highlight rules from <i>%1</i>?"
678 ).arg(localHighlightsName),
679 QMessageBox::Yes|QMessageBox::No,
682 if (ret != QMessageBox::Yes) {
683 // Only two options, Yes or No, return if not Yes
687 auto clonedManager = HighlightRuleManager();
688 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
690 for (const auto &variant : notificationSettings.highlightList()) {
691 auto highlightRule = variant.toMap();
693 clonedManager.addHighlightRule(
694 highlightRule["Name"].toString(),
695 highlightRule["RegEx"].toBool(),
696 highlightRule["CS"].toBool(),
697 highlightRule["Enable"].toBool(),
700 highlightRule["Channel"].toString()
704 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
705 setChangedState(false);
708 // Give a heads-up that all succeeded
709 QMessageBox::information(this,
710 tr("Imported highlights"),
711 tr("%1 highlight rules successfully imported."
712 ).arg(QString::number(localHighlightList.count())));
715 bool CoreHighlightSettingsPage::isSelectable() const {
716 return Client::isConnected();
717 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
718 // a friendly error message.