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"),
36 // In Monolithic mode, local highlights are replaced by remote highlights
37 Quassel::runMode() == Quassel::Monolithic ? tr("Highlights") : tr("Remote Highlights"),
42 setupRuleTable(ui.highlightTable);
43 setupRuleTable(ui.ignoredTable);
45 ui.highlightNicksComboBox->addItem(tr("All Nicks from Identity"), QVariant(HighlightRuleManager::AllNicks));
46 ui.highlightNicksComboBox->addItem(tr("Current Nick"), QVariant(HighlightRuleManager::CurrentNick));
47 ui.highlightNicksComboBox->addItem(tr("None"), QVariant(HighlightRuleManager::NoNick));
49 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
50 connect(Client::instance(), &Client::coreConnectionStateChanged, this, &CoreHighlightSettingsPage::coreConnectionStateChanged);
52 connect(ui.highlightAdd, &QAbstractButton::clicked, this, [this]() { addNewHighlightRow(); });
53 connect(ui.highlightRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::removeSelectedHighlightRows);
54 connect(ui.highlightImport, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::importRules);
56 connect(ui.ignoredAdd, &QAbstractButton::clicked, this, [this]() { addNewIgnoredRow(); });
57 connect(ui.ignoredRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::removeSelectedIgnoredRows);
59 // TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
60 connect(ui.highlightTable, &QTableWidget::itemClicked, this, &CoreHighlightSettingsPage::selectHighlightRow);
61 connect(ui.ignoredTable, &QTableWidget::itemClicked, this, &CoreHighlightSettingsPage::selectIgnoredRow);
63 // Update the "Case sensitive" checkbox
64 connect(ui.highlightNicksComboBox,
65 selectOverload<int>(&QComboBox::currentIndexChanged),
67 &CoreHighlightSettingsPage::highlightNicksChanged);
68 connect(ui.highlightNicksComboBox, selectOverload<int>(&QComboBox::currentIndexChanged), this, &CoreHighlightSettingsPage::widgetHasChanged);
69 connect(ui.nicksCaseSensitive, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
71 connect(ui.highlightAdd, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
72 connect(ui.highlightRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
74 connect(ui.ignoredAdd, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
75 connect(ui.ignoredRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
77 connect(ui.highlightTable, &QTableWidget::itemChanged, this, &CoreHighlightSettingsPage::highlightTableChanged);
79 connect(ui.ignoredTable, &QTableWidget::itemChanged, this, &CoreHighlightSettingsPage::ignoredTableChanged);
81 connect(Client::instance(), &Client::connected, this, &CoreHighlightSettingsPage::clientConnected);
84 ui.coreUnsupportedIcon->setPixmap(icon::get("dialog-warning").pixmap(16));
86 // Set up client/monolithic remote highlights information
87 if (Quassel::runMode() == Quassel::Monolithic) {
88 // We're running in Monolithic mode, local highlights are considered legacy
89 ui.highlightImport->setText(tr("Import Legacy"));
90 ui.highlightImport->setToolTip(
91 tr("Import highlight rules configured in <i>%1</i>.").arg(tr("Legacy Highlights").replace(" ", " ")));
92 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing
93 // all spaces to be non-breaking
96 // We're running in client/split mode, local highlights are distinguished from remote
97 ui.highlightImport->setText(tr("Import Local"));
98 ui.highlightImport->setToolTip(
99 tr("Import highlight rules configured in <i>%1</i>.").arg(tr("Local Highlights").replace(" ", " ")));
100 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing
101 // all spaces to be non-breaking
105 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
107 updateCoreSupportStatus(state);
117 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget* table) const
119 table->verticalHeader()->hide();
120 table->setShowGrid(false);
122 setupTableTooltips(table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn),
123 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn),
124 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn),
125 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn),
126 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn),
127 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn));
129 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
130 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
131 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
132 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
133 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
134 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
137 QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
139 switch (tableColumn) {
140 case CoreHighlightSettingsPage::EnableColumn:
141 return tr("Enable/disable this rule");
143 case CoreHighlightSettingsPage::NameColumn:
144 return tr("Phrase to match, leave blank to match any message");
146 case CoreHighlightSettingsPage::RegExColumn:
147 return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
148 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
151 case CoreHighlightSettingsPage::CsColumn:
152 return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
153 "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
155 case CoreHighlightSettingsPage::SenderColumn:
156 return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
157 "leave blank to match any nickname.</p>"
158 "<p><i>Example:</i><br />"
159 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
160 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
161 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
162 "<p>If only inverted names are specified, it will match anything except for "
163 "what's specified (implicit wildcard).</p>"
164 "<p><i>Example:</i><br />"
165 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
166 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
167 "any nickname starting with <i>Announce</i></p>");
169 case CoreHighlightSettingsPage::ChanColumn:
170 return tr("<p><b>Channel</b>: Semicolon separated list of channel/query names, leave blank "
171 "to match any name.</p>"
172 "<p><i>Example:</i><br />"
173 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
174 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
175 "except for <i>#quasseldroid</i><br />"
176 "<p>If only inverted names are specified, it will match anything except for "
177 "what's specified (implicit wildcard).</p>"
178 "<p><i>Example:</i><br />"
179 "<i>!#quassel*; !#foobar</i><br />"
180 "would match anything except for <i>#foobar</i> or any channel starting with "
181 "<i>#quassel</i></p>");
184 // This shouldn't happen
185 return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
189 void CoreHighlightSettingsPage::setupTableTooltips(
190 QWidget* enableWidget, QWidget* nameWidget, QWidget* regExWidget, QWidget* csWidget, QWidget* senderWidget, QWidget* chanWidget) const
192 // Make sure everything's valid
193 Q_ASSERT(enableWidget);
194 Q_ASSERT(nameWidget);
195 Q_ASSERT(regExWidget);
197 Q_ASSERT(senderWidget);
198 Q_ASSERT(chanWidget);
200 // Set tooltips and "What's this?" prompts
202 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
203 enableWidget->setWhatsThis(enableWidget->toolTip());
206 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
207 nameWidget->setWhatsThis(nameWidget->toolTip());
210 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
211 regExWidget->setWhatsThis(regExWidget->toolTip());
214 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
215 csWidget->setWhatsThis(csWidget->toolTip());
218 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
219 senderWidget->setWhatsThis(senderWidget->toolTip());
221 // Channel/buffer name
222 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
223 chanWidget->setWhatsThis(chanWidget->toolTip());
226 void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem* enableWidget,
227 QTableWidgetItem* nameWidget,
228 QTableWidgetItem* regExWidget,
229 QTableWidgetItem* csWidget,
230 QTableWidgetItem* senderWidget,
231 QTableWidgetItem* chanWidget) const
233 // Make sure everything's valid
234 Q_ASSERT(enableWidget);
235 Q_ASSERT(nameWidget);
236 Q_ASSERT(regExWidget);
238 Q_ASSERT(senderWidget);
239 Q_ASSERT(chanWidget);
241 // Set tooltips and "What's this?" prompts
243 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
244 enableWidget->setWhatsThis(enableWidget->toolTip());
247 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
248 nameWidget->setWhatsThis(nameWidget->toolTip());
251 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
252 regExWidget->setWhatsThis(regExWidget->toolTip());
255 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
256 csWidget->setWhatsThis(csWidget->toolTip());
259 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
260 senderWidget->setWhatsThis(senderWidget->toolTip());
262 // Channel/buffer name
263 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
264 chanWidget->setWhatsThis(chanWidget->toolTip());
267 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
269 // Assume connected state as enforced by the settings page UI
270 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
271 // Either disconnected or core supports highlights, enable highlight configuration and hide
272 // warning. Don't show the warning needlessly when disconnected.
273 ui.highlightsConfigWidget->setEnabled(true);
274 ui.coreUnsupportedWidget->setVisible(false);
277 // Core does not support highlights, show warning and disable highlight configuration
278 ui.highlightsConfigWidget->setEnabled(false);
279 ui.coreUnsupportedWidget->setVisible(true);
283 void CoreHighlightSettingsPage::clientConnected()
285 connect(Client::highlightRuleManager(), &SyncableObject::updated, this, &CoreHighlightSettingsPage::revert);
288 void CoreHighlightSettingsPage::revert()
293 setChangedState(false);
297 bool CoreHighlightSettingsPage::hasDefaults() const
302 void CoreHighlightSettingsPage::defaults()
304 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
305 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
306 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
307 ui.nicksCaseSensitive->setChecked(false);
308 emptyHighlightTable();
314 void CoreHighlightSettingsPage::addNewHighlightRow(
315 bool enable, int id, const QString& name, bool regex, bool cs, const QString& sender, const QString& chanName, bool self)
317 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
323 auto* nameItem = new QTableWidgetItem(name);
325 auto* regexItem = new QTableWidgetItem("");
327 regexItem->setCheckState(Qt::Checked);
329 regexItem->setCheckState(Qt::Unchecked);
330 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
332 auto* csItem = new QTableWidgetItem("");
334 csItem->setCheckState(Qt::Checked);
336 csItem->setCheckState(Qt::Unchecked);
337 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
339 auto* enableItem = new QTableWidgetItem("");
341 enableItem->setCheckState(Qt::Checked);
343 enableItem->setCheckState(Qt::Unchecked);
344 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
346 auto* senderItem = new QTableWidgetItem(sender);
348 auto* chanNameItem = new QTableWidgetItem(chanName);
350 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
352 int lastRow = ui.highlightTable->rowCount() - 1;
353 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
354 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
355 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
356 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
357 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
358 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
361 ui.highlightTable->setCurrentItem(nameItem);
363 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
366 void CoreHighlightSettingsPage::addNewIgnoredRow(
367 bool enable, int id, const QString& name, bool regex, bool cs, const QString& sender, const QString& chanName, bool self)
369 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
375 auto* nameItem = new QTableWidgetItem(name);
377 auto* regexItem = new QTableWidgetItem("");
379 regexItem->setCheckState(Qt::Checked);
381 regexItem->setCheckState(Qt::Unchecked);
382 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
384 auto* csItem = new QTableWidgetItem("");
386 csItem->setCheckState(Qt::Checked);
388 csItem->setCheckState(Qt::Unchecked);
389 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
391 auto* enableItem = new QTableWidgetItem("");
393 enableItem->setCheckState(Qt::Checked);
395 enableItem->setCheckState(Qt::Unchecked);
396 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
398 auto* chanNameItem = new QTableWidgetItem(chanName);
400 auto* senderItem = new QTableWidgetItem(sender);
402 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
404 int lastRow = ui.ignoredTable->rowCount() - 1;
405 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
406 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
407 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
408 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
409 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
410 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
413 ui.ignoredTable->setCurrentItem(nameItem);
415 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
418 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
420 QList<int> selectedRows;
421 QList<QTableWidgetItem*> selectedItemList = ui.highlightTable->selectedItems();
422 for (auto selectedItem : selectedItemList) {
423 selectedRows.append(selectedItem->row());
425 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
427 for (auto row : selectedRows) {
428 if (row != lastRow) {
429 ui.highlightTable->removeRow(row);
430 highlightList.removeAt(row);
436 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
438 QList<int> selectedRows;
439 QList<QTableWidgetItem*> selectedItemList = ui.ignoredTable->selectedItems();
440 for (auto selectedItem : selectedItemList) {
441 selectedRows.append(selectedItem->row());
443 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
445 for (auto row : selectedRows) {
446 if (row != lastRow) {
447 ui.ignoredTable->removeRow(row);
448 ignoredList.removeAt(row);
454 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
456 // Only allow toggling "Case sensitive" when a nickname will be highlighted
457 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
458 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
461 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem* item)
463 int row = item->row();
464 bool selected = item->isSelected();
465 ui.highlightTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1), selected);
468 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem* item)
470 int row = item->row();
471 bool selected = item->isSelected();
472 ui.ignoredTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1), selected);
475 void CoreHighlightSettingsPage::emptyHighlightTable()
477 // ui.highlight and highlightList should have the same size, but just to make sure.
478 if (ui.highlightTable->rowCount() != highlightList.size()) {
479 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
481 while (ui.highlightTable->rowCount()) {
482 ui.highlightTable->removeRow(0);
484 highlightList.clear();
487 void CoreHighlightSettingsPage::emptyIgnoredTable()
489 // ui.highlight and highlightList should have the same size, but just to make sure.
490 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
491 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
493 while (ui.ignoredTable->rowCount()) {
494 ui.ignoredTable->removeRow(0);
499 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem* item)
501 if (item->row() + 1 > highlightList.size())
504 auto highlightRule = highlightList.value(item->row());
506 switch (item->column()) {
507 case CoreHighlightSettingsPage::EnableColumn:
508 highlightRule.setIsEnabled(item->checkState() == Qt::Checked);
510 case CoreHighlightSettingsPage::NameColumn:
511 highlightRule.setContents(item->text());
513 case CoreHighlightSettingsPage::RegExColumn:
514 highlightRule.setIsRegEx(item->checkState() == Qt::Checked);
516 case CoreHighlightSettingsPage::CsColumn:
517 highlightRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
519 case CoreHighlightSettingsPage::SenderColumn:
520 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
522 highlightRule.setSender(item->text());
524 case CoreHighlightSettingsPage::ChanColumn:
525 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
527 highlightRule.setChanName(item->text());
530 highlightList[item->row()] = highlightRule;
531 emit widgetHasChanged();
534 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem* item)
536 if (item->row() + 1 > ignoredList.size())
539 auto ignoredRule = ignoredList.value(item->row());
541 switch (item->column()) {
542 case CoreHighlightSettingsPage::EnableColumn:
543 ignoredRule.setIsEnabled(item->checkState() == Qt::Checked);
545 case CoreHighlightSettingsPage::NameColumn:
546 ignoredRule.setContents(item->text());
548 case CoreHighlightSettingsPage::RegExColumn:
549 ignoredRule.setIsRegEx(item->checkState() == Qt::Checked);
551 case CoreHighlightSettingsPage::CsColumn:
552 ignoredRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
554 case CoreHighlightSettingsPage::SenderColumn:
555 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
557 ignoredRule.setSender(item->text());
559 case CoreHighlightSettingsPage::ChanColumn:
560 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
562 ignoredRule.setChanName(item->text());
565 ignoredList[item->row()] = ignoredRule;
566 emit widgetHasChanged();
569 void CoreHighlightSettingsPage::load()
571 emptyHighlightTable();
574 auto ruleManager = Client::highlightRuleManager();
576 for (auto& rule : ruleManager->highlightRuleList()) {
577 if (rule.isInverse()) {
578 addNewIgnoredRow(rule.isEnabled(),
582 rule.isCaseSensitive(),
587 addNewHighlightRow(rule.isEnabled(),
591 rule.isCaseSensitive(),
597 int highlightNickType = ruleManager->highlightNick();
598 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
599 // Trigger the initial update of nicksCaseSensitive being enabled or not
600 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
601 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
603 setChangedState(false);
611 void CoreHighlightSettingsPage::save()
619 auto ruleManager = Client::highlightRuleManager();
620 if (ruleManager == nullptr)
623 HighlightRuleManager clonedManager;
624 clonedManager.fromVariantMap(ruleManager->toVariantMap());
625 clonedManager.clear();
627 for (auto& rule : highlightList) {
628 clonedManager.addHighlightRule(rule.id(),
631 rule.isCaseSensitive(),
638 for (auto& rule : ignoredList) {
639 clonedManager.addHighlightRule(rule.id(),
642 rule.isCaseSensitive(),
649 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
651 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
652 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
654 ruleManager->requestUpdate(clonedManager.toVariantMap());
655 setChangedState(false);
659 int CoreHighlightSettingsPage::nextId()
662 for (int i = 0; i < highlightList.count(); i++) {
663 int id = highlightList[i].id();
668 for (int i = 0; i < ignoredList.count(); i++) {
669 int id = ignoredList[i].id();
677 void CoreHighlightSettingsPage::widgetHasChanged()
679 setChangedState(true);
682 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
684 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
685 // spaces to non-breaking
686 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
688 const QString remoteHighlightsMsgText = QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>")
689 .arg(tr("Your Quassel core is too old to support remote highlights"),
690 tr("You need a Quassel core v0.13.0 or newer to configure remote "
692 tr("You can still configure highlights for this device only in "
694 .arg(localHighlightsName));
696 QMessageBox::warning(this, tr("Remote Highlights unsupported"), remoteHighlightsMsgText);
699 void CoreHighlightSettingsPage::importRules()
701 NotificationSettings notificationSettings;
703 const auto localHighlightList = notificationSettings.highlightList();
705 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
706 // forcing all spaces to non-breaking
707 QString localHighlightsName;
708 if (Quassel::runMode() == Quassel::Monolithic) {
709 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
712 localHighlightsName = tr("Local Highlights").replace(" ", " ");
715 if (localHighlightList.count() == 0) {
716 // No highlight rules exist to import, do nothing
717 QMessageBox::information(this, tr("No highlights to import"), tr("No highlight rules in <i>%1</i>.").arg(localHighlightsName));
721 int ret = QMessageBox::question(this,
722 tr("Import highlights?"),
723 tr("Import all highlight rules from <i>%1</i>?").arg(localHighlightsName),
724 QMessageBox::Yes | QMessageBox::No,
727 if (ret != QMessageBox::Yes) {
728 // Only two options, Yes or No, return if not Yes
733 // Save existing changes first to avoid overwriting them
737 HighlightRuleManager clonedManager;
738 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
740 for (const auto& variant : notificationSettings.highlightList()) {
741 auto highlightRule = variant.toMap();
743 clonedManager.addHighlightRule(clonedManager.nextId(),
744 highlightRule["Name"].toString(),
745 highlightRule["RegEx"].toBool(),
746 highlightRule["CS"].toBool(),
747 highlightRule["Enable"].toBool(),
750 highlightRule["Channel"].toString());
753 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
754 setChangedState(false);
757 // Give a heads-up that all succeeded
758 QMessageBox::information(this,
759 tr("Imported highlights"),
760 tr("%1 highlight rules successfully imported.").arg(QString::number(localHighlightList.count())));
763 bool CoreHighlightSettingsPage::isSelectable() const
765 return Client::isConnected();
766 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
767 // a friendly error message.