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 "corehighlightsettingspage.h"
25 #include <QHeaderView>
26 #include <QMessageBox>
27 #include <QTableWidget>
34 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget* parent)
35 : SettingsPage(tr("Interface"), tr("Highlights"),
40 setupRuleTable(ui.highlightTable);
41 setupRuleTable(ui.ignoredTable);
43 ui.highlightNicksComboBox->addItem(tr("All Nicks from Identity"), QVariant(HighlightRuleManager::AllNicks));
44 ui.highlightNicksComboBox->addItem(tr("Current Nick"), QVariant(HighlightRuleManager::CurrentNick));
45 ui.highlightNicksComboBox->addItem(tr("None"), QVariant(HighlightRuleManager::NoNick));
47 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
48 connect(Client::instance(), &Client::coreConnectionStateChanged, this, &CoreHighlightSettingsPage::coreConnectionStateChanged);
50 connect(ui.highlightAdd, &QAbstractButton::clicked, this, [this]() { addNewHighlightRow(); });
51 connect(ui.highlightRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::removeSelectedHighlightRows);
52 connect(ui.highlightImport, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::importRules);
54 connect(ui.ignoredAdd, &QAbstractButton::clicked, this, [this]() { addNewIgnoredRow(); });
55 connect(ui.ignoredRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::removeSelectedIgnoredRows);
57 // TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
58 connect(ui.highlightTable, &QTableWidget::itemClicked, this, &CoreHighlightSettingsPage::selectHighlightRow);
59 connect(ui.ignoredTable, &QTableWidget::itemClicked, this, &CoreHighlightSettingsPage::selectIgnoredRow);
61 // Update the "Case sensitive" checkbox
62 connect(ui.highlightNicksComboBox,
63 selectOverload<int>(&QComboBox::currentIndexChanged),
65 &CoreHighlightSettingsPage::highlightNicksChanged);
66 connect(ui.highlightNicksComboBox, selectOverload<int>(&QComboBox::currentIndexChanged), this, &CoreHighlightSettingsPage::widgetHasChanged);
67 connect(ui.nicksCaseSensitive, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
69 connect(ui.highlightAdd, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
70 connect(ui.highlightRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
72 connect(ui.ignoredAdd, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
73 connect(ui.ignoredRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
75 connect(ui.highlightTable, &QTableWidget::itemChanged, this, &CoreHighlightSettingsPage::highlightTableChanged);
77 connect(ui.ignoredTable, &QTableWidget::itemChanged, this, &CoreHighlightSettingsPage::ignoredTableChanged);
79 connect(Client::instance(), &Client::connected, this, &CoreHighlightSettingsPage::clientConnected);
82 ui.coreUnsupportedIcon->setPixmap(icon::get({"emblem-unavailable", "dialog-warning"}).pixmap(16));
84 // Set up client/monolithic remote highlights information
85 // Local highlights are considered legacy
86 ui.highlightImport->setText(tr("Import Legacy"));
87 ui.highlightImport->setToolTip(
88 tr("Import highlight rules configured in <i>%1</i>.").arg(tr("Legacy Highlights").replace(" ", " ")));
89 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing
90 // all spaces to be non-breaking
93 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
95 updateCoreSupportStatus(state);
105 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget* table) const
107 table->verticalHeader()->hide();
108 table->setShowGrid(false);
110 setupTableTooltips(table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn),
111 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn),
112 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn),
113 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn),
114 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn),
115 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn));
117 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
118 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
119 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
120 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
121 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
122 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
125 QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
127 switch (tableColumn) {
128 case CoreHighlightSettingsPage::EnableColumn:
129 return tr("Enable/disable this rule");
131 case CoreHighlightSettingsPage::NameColumn:
132 return tr("Phrase to match, leave blank to match any message");
134 case CoreHighlightSettingsPage::RegExColumn:
135 return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
136 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
139 case CoreHighlightSettingsPage::CsColumn:
140 return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
141 "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
143 case CoreHighlightSettingsPage::SenderColumn:
144 return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
145 "leave blank to match any nickname.</p>"
146 "<p><i>Example:</i><br />"
147 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
148 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
149 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
150 "<p>If only inverted names are specified, it will match anything except for "
151 "what's specified (implicit wildcard).</p>"
152 "<p><i>Example:</i><br />"
153 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
154 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
155 "any nickname starting with <i>Announce</i></p>");
157 case CoreHighlightSettingsPage::ChanColumn:
158 return tr("<p><b>Channel</b>: Semicolon separated list of channel/query names, leave blank "
159 "to match any name.</p>"
160 "<p><i>Example:</i><br />"
161 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
162 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
163 "except for <i>#quasseldroid</i><br />"
164 "<p>If only inverted names are specified, it will match anything except for "
165 "what's specified (implicit wildcard).</p>"
166 "<p><i>Example:</i><br />"
167 "<i>!#quassel*; !#foobar</i><br />"
168 "would match anything except for <i>#foobar</i> or any channel starting with "
169 "<i>#quassel</i></p>");
172 // This shouldn't happen
173 return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
177 void CoreHighlightSettingsPage::setupTableTooltips(
178 QWidget* enableWidget, QWidget* nameWidget, QWidget* regExWidget, QWidget* csWidget, QWidget* senderWidget, QWidget* chanWidget) const
180 // Make sure everything's valid
181 Q_ASSERT(enableWidget);
182 Q_ASSERT(nameWidget);
183 Q_ASSERT(regExWidget);
185 Q_ASSERT(senderWidget);
186 Q_ASSERT(chanWidget);
188 // Set tooltips and "What's this?" prompts
190 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
191 enableWidget->setWhatsThis(enableWidget->toolTip());
194 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
195 nameWidget->setWhatsThis(nameWidget->toolTip());
198 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
199 regExWidget->setWhatsThis(regExWidget->toolTip());
202 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
203 csWidget->setWhatsThis(csWidget->toolTip());
206 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
207 senderWidget->setWhatsThis(senderWidget->toolTip());
209 // Channel/buffer name
210 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
211 chanWidget->setWhatsThis(chanWidget->toolTip());
214 void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem* enableWidget,
215 QTableWidgetItem* nameWidget,
216 QTableWidgetItem* regExWidget,
217 QTableWidgetItem* csWidget,
218 QTableWidgetItem* senderWidget,
219 QTableWidgetItem* chanWidget) const
221 // Make sure everything's valid
222 Q_ASSERT(enableWidget);
223 Q_ASSERT(nameWidget);
224 Q_ASSERT(regExWidget);
226 Q_ASSERT(senderWidget);
227 Q_ASSERT(chanWidget);
229 // Set tooltips and "What's this?" prompts
231 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
232 enableWidget->setWhatsThis(enableWidget->toolTip());
235 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
236 nameWidget->setWhatsThis(nameWidget->toolTip());
239 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
240 regExWidget->setWhatsThis(regExWidget->toolTip());
243 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
244 csWidget->setWhatsThis(csWidget->toolTip());
247 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
248 senderWidget->setWhatsThis(senderWidget->toolTip());
250 // Channel/buffer name
251 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
252 chanWidget->setWhatsThis(chanWidget->toolTip());
255 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
257 // Assume connected state as enforced by the settings page UI
258 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
259 // Either disconnected or core supports highlights, enable highlight configuration and hide
260 // warning. Don't show the warning needlessly when disconnected.
261 ui.highlightsConfigWidget->setEnabled(true);
262 ui.coreUnsupportedWidget->setVisible(false);
265 // Core does not support highlights, show warning and disable highlight configuration
266 ui.highlightsConfigWidget->setEnabled(false);
267 ui.coreUnsupportedWidget->setVisible(true);
271 void CoreHighlightSettingsPage::clientConnected()
273 connect(Client::highlightRuleManager(), &SyncableObject::updated, this, &CoreHighlightSettingsPage::revert);
276 void CoreHighlightSettingsPage::revert()
281 setChangedState(false);
285 bool CoreHighlightSettingsPage::hasDefaults() const
290 void CoreHighlightSettingsPage::defaults()
292 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
293 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
294 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
295 ui.nicksCaseSensitive->setChecked(false);
296 emptyHighlightTable();
302 void CoreHighlightSettingsPage::addNewHighlightRow(
303 bool enable, int id, const QString& name, bool regex, bool cs, const QString& sender, const QString& chanName, bool self)
305 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
311 auto* nameItem = new QTableWidgetItem(name);
313 auto* regexItem = new QTableWidgetItem("");
315 regexItem->setCheckState(Qt::Checked);
317 regexItem->setCheckState(Qt::Unchecked);
318 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
320 auto* csItem = new QTableWidgetItem("");
322 csItem->setCheckState(Qt::Checked);
324 csItem->setCheckState(Qt::Unchecked);
325 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
327 auto* enableItem = new QTableWidgetItem("");
329 enableItem->setCheckState(Qt::Checked);
331 enableItem->setCheckState(Qt::Unchecked);
332 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
334 auto* senderItem = new QTableWidgetItem(sender);
336 auto* chanNameItem = new QTableWidgetItem(chanName);
338 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
340 int lastRow = ui.highlightTable->rowCount() - 1;
341 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
342 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
343 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
344 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
345 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
346 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
349 ui.highlightTable->setCurrentItem(nameItem);
351 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
354 void CoreHighlightSettingsPage::addNewIgnoredRow(
355 bool enable, int id, const QString& name, bool regex, bool cs, const QString& sender, const QString& chanName, bool self)
357 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
363 auto* nameItem = new QTableWidgetItem(name);
365 auto* regexItem = new QTableWidgetItem("");
367 regexItem->setCheckState(Qt::Checked);
369 regexItem->setCheckState(Qt::Unchecked);
370 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
372 auto* csItem = new QTableWidgetItem("");
374 csItem->setCheckState(Qt::Checked);
376 csItem->setCheckState(Qt::Unchecked);
377 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
379 auto* enableItem = new QTableWidgetItem("");
381 enableItem->setCheckState(Qt::Checked);
383 enableItem->setCheckState(Qt::Unchecked);
384 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
386 auto* chanNameItem = new QTableWidgetItem(chanName);
388 auto* senderItem = new QTableWidgetItem(sender);
390 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
392 int lastRow = ui.ignoredTable->rowCount() - 1;
393 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
394 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
395 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
396 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
397 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
398 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
401 ui.ignoredTable->setCurrentItem(nameItem);
403 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
406 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
408 QList<int> selectedRows;
409 QList<QTableWidgetItem*> selectedItemList = ui.highlightTable->selectedItems();
410 for (auto selectedItem : selectedItemList) {
411 selectedRows.append(selectedItem->row());
413 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
415 for (auto row : selectedRows) {
416 if (row != lastRow) {
417 ui.highlightTable->removeRow(row);
418 highlightList.removeAt(row);
424 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
426 QList<int> selectedRows;
427 QList<QTableWidgetItem*> selectedItemList = ui.ignoredTable->selectedItems();
428 for (auto selectedItem : selectedItemList) {
429 selectedRows.append(selectedItem->row());
431 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
433 for (auto row : selectedRows) {
434 if (row != lastRow) {
435 ui.ignoredTable->removeRow(row);
436 ignoredList.removeAt(row);
442 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
444 // Only allow toggling "Case sensitive" when a nickname will be highlighted
445 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
446 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
449 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem* item)
451 int row = item->row();
452 bool selected = item->isSelected();
453 ui.highlightTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1), selected);
456 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem* item)
458 int row = item->row();
459 bool selected = item->isSelected();
460 ui.ignoredTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1), selected);
463 void CoreHighlightSettingsPage::emptyHighlightTable()
465 // ui.highlight and highlightList should have the same size, but just to make sure.
466 if (ui.highlightTable->rowCount() != highlightList.size()) {
467 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
469 while (ui.highlightTable->rowCount()) {
470 ui.highlightTable->removeRow(0);
472 highlightList.clear();
475 void CoreHighlightSettingsPage::emptyIgnoredTable()
477 // ui.highlight and highlightList should have the same size, but just to make sure.
478 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
479 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
481 while (ui.ignoredTable->rowCount()) {
482 ui.ignoredTable->removeRow(0);
487 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem* item)
489 if (item->row() + 1 > highlightList.size())
492 auto highlightRule = highlightList.value(item->row());
494 switch (item->column()) {
495 case CoreHighlightSettingsPage::EnableColumn:
496 highlightRule.setIsEnabled(item->checkState() == Qt::Checked);
498 case CoreHighlightSettingsPage::NameColumn:
499 highlightRule.setContents(item->text());
501 case CoreHighlightSettingsPage::RegExColumn:
502 highlightRule.setIsRegEx(item->checkState() == Qt::Checked);
504 case CoreHighlightSettingsPage::CsColumn:
505 highlightRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
507 case CoreHighlightSettingsPage::SenderColumn:
508 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
510 highlightRule.setSender(item->text());
512 case CoreHighlightSettingsPage::ChanColumn:
513 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
515 highlightRule.setChanName(item->text());
518 highlightList[item->row()] = highlightRule;
519 emit widgetHasChanged();
522 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem* item)
524 if (item->row() + 1 > ignoredList.size())
527 auto ignoredRule = ignoredList.value(item->row());
529 switch (item->column()) {
530 case CoreHighlightSettingsPage::EnableColumn:
531 ignoredRule.setIsEnabled(item->checkState() == Qt::Checked);
533 case CoreHighlightSettingsPage::NameColumn:
534 ignoredRule.setContents(item->text());
536 case CoreHighlightSettingsPage::RegExColumn:
537 ignoredRule.setIsRegEx(item->checkState() == Qt::Checked);
539 case CoreHighlightSettingsPage::CsColumn:
540 ignoredRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
542 case CoreHighlightSettingsPage::SenderColumn:
543 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
545 ignoredRule.setSender(item->text());
547 case CoreHighlightSettingsPage::ChanColumn:
548 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
550 ignoredRule.setChanName(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(),
570 rule.isCaseSensitive(),
575 addNewHighlightRow(rule.isEnabled(),
579 rule.isCaseSensitive(),
585 int highlightNickType = ruleManager->highlightNick();
586 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
587 // Trigger the initial update of nicksCaseSensitive being enabled or not
588 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
589 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
591 setChangedState(false);
599 void CoreHighlightSettingsPage::save()
607 auto ruleManager = Client::highlightRuleManager();
608 if (ruleManager == nullptr)
611 HighlightRuleManager clonedManager;
612 clonedManager.fromVariantMap(ruleManager->toVariantMap());
613 clonedManager.clear();
615 for (auto& rule : highlightList) {
616 clonedManager.addHighlightRule(rule.id(),
619 rule.isCaseSensitive(),
626 for (auto& rule : ignoredList) {
627 clonedManager.addHighlightRule(rule.id(),
630 rule.isCaseSensitive(),
637 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
639 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
640 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
642 ruleManager->requestUpdate(clonedManager.toVariantMap());
643 setChangedState(false);
647 int CoreHighlightSettingsPage::nextId()
650 for (int i = 0; i < highlightList.count(); i++) {
651 int id = highlightList[i].id();
656 for (int i = 0; i < ignoredList.count(); i++) {
657 int id = ignoredList[i].id();
665 void CoreHighlightSettingsPage::widgetHasChanged()
667 setChangedState(true);
670 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
672 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing all
673 // spaces to non-breaking
674 const QString localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
676 const QString remoteHighlightsMsgText = QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>")
677 .arg(tr("Your Quassel core is too old to support remote highlights"),
678 tr("You need a Quassel core v0.13.0 or newer to configure remote "
680 tr("You can still configure highlights for this device only in "
682 .arg(localHighlightsName));
684 QMessageBox::warning(this, tr("Remote Highlights unsupported"), remoteHighlightsMsgText);
687 void CoreHighlightSettingsPage::importRules()
689 NotificationSettings notificationSettings;
691 const auto localHighlightList = notificationSettings.highlightList();
693 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
694 // forcing all spaces to non-breaking
695 // "Local Highlights" has been removed; it's always called "Legacy" now.
696 QString localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
698 if (localHighlightList.count() == 0) {
699 // No highlight rules exist to import, do nothing
700 QMessageBox::information(this, tr("No highlights to import"), tr("No highlight rules in <i>%1</i>.").arg(localHighlightsName));
704 int ret = QMessageBox::question(this,
705 tr("Import highlights?"),
706 tr("Import all highlight rules from <i>%1</i>?").arg(localHighlightsName),
707 QMessageBox::Yes | QMessageBox::No,
710 if (ret != QMessageBox::Yes) {
711 // Only two options, Yes or No, return if not Yes
716 // Save existing changes first to avoid overwriting them
720 HighlightRuleManager clonedManager;
721 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
723 for (const auto& variant : notificationSettings.highlightList()) {
724 auto highlightRule = variant.toMap();
726 clonedManager.addHighlightRule(clonedManager.nextId(),
727 highlightRule["Name"].toString(),
728 highlightRule["RegEx"].toBool(),
729 highlightRule["CS"].toBool(),
730 highlightRule["Enable"].toBool(),
733 highlightRule["Channel"].toString());
736 // Copy nickname highlighting settings
737 clonedManager.setNicksCaseSensitive(notificationSettings.nicksCaseSensitive());
738 if (notificationSettings.highlightNick() == NotificationSettings::HighlightNickType::AllNicks) {
739 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType::AllNicks);
741 else if (notificationSettings.highlightNick() == NotificationSettings::HighlightNickType::CurrentNick) {
742 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType::CurrentNick);
744 // else - Don't copy "NoNick", "NoNick" is now default and should be ignored
746 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
747 setChangedState(false);
750 // Give a heads-up that all succeeded, ask about removing old rules
752 // Hypothetically, someone might use a common set of highlight rules across multiple cores.
753 // This won't matter once client highlights are disabled entirely on newer cores.
755 // Remove this once client-side highlights are disabled for newer cores.
756 ret = QMessageBox::question(this, tr("Imported highlights"),
757 QString("<p>%1</p></br><p>%2</p>").arg(
758 tr("%1 highlight rules successfully imported.").arg(QString::number(localHighlightList.count())),
759 tr("Clean up old, duplicate highlight rules?")),
760 QMessageBox::Yes | QMessageBox::No,
763 if (ret != QMessageBox::Yes) {
764 // Only two options, Yes or No, return if not Yes
768 // Remove all local highlight rules
769 notificationSettings.setHighlightList({});
770 // Disable local nickname highlighting
771 notificationSettings.setHighlightNick(NotificationSettings::HighlightNickType::NoNick);
772 // Disable nickname sensitivity
773 // This isn't needed to disable local highlights, but it's part of appearing reset-to-default
774 notificationSettings.setNicksCaseSensitive(false);
776 // Refresh HighlightSettingsPage in case it was already loaded
777 emit localHighlightsChanged();
780 bool CoreHighlightSettingsPage::isSelectable() const
782 return Client::isConnected();
783 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
784 // a friendly error message.