1 /***************************************************************************
2 * Copyright (C) 2005-2019 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"
23 #include <QHeaderView>
24 #include <QMessageBox>
25 #include <QTableWidget>
32 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget* parent)
33 : SettingsPage(tr("Interface"),
34 // In Monolithic mode, local highlights are replaced by remote highlights
35 Quassel::runMode() == Quassel::Monolithic ? tr("Highlights") : tr("Remote 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("dialog-warning").pixmap(16));
84 // Set up client/monolithic remote highlights information
85 if (Quassel::runMode() == Quassel::Monolithic) {
86 // We're running in Monolithic mode, local highlights are considered legacy
87 ui.highlightImport->setText(tr("Import Legacy"));
88 ui.highlightImport->setToolTip(
89 tr("Import highlight rules configured in <i>%1</i>.").arg(tr("Legacy Highlights").replace(" ", " ")));
90 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing
91 // all spaces to be non-breaking
94 // We're running in client/split mode, local highlights are distinguished from remote
95 ui.highlightImport->setText(tr("Import Local"));
96 ui.highlightImport->setToolTip(
97 tr("Import highlight rules configured in <i>%1</i>.").arg(tr("Local Highlights").replace(" ", " ")));
98 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing
99 // all spaces to be non-breaking
103 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
105 updateCoreSupportStatus(state);
115 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget* table) const
117 table->verticalHeader()->hide();
118 table->setShowGrid(false);
120 setupTableTooltips(table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn),
121 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn),
122 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn),
123 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn),
124 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn),
125 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn));
127 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
128 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
129 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
130 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
131 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
132 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
135 QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
137 switch (tableColumn) {
138 case CoreHighlightSettingsPage::EnableColumn:
139 return tr("Enable/disable this rule");
141 case CoreHighlightSettingsPage::NameColumn:
142 return tr("Phrase to match, leave blank to match any message");
144 case CoreHighlightSettingsPage::RegExColumn:
145 return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
146 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
149 case CoreHighlightSettingsPage::CsColumn:
150 return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
151 "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
153 case CoreHighlightSettingsPage::SenderColumn:
154 return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
155 "leave blank to match any nickname.</p>"
156 "<p><i>Example:</i><br />"
157 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
158 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
159 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
160 "<p>If only inverted names are specified, it will match anything except for "
161 "what's specified (implicit wildcard).</p>"
162 "<p><i>Example:</i><br />"
163 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
164 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
165 "any nickname starting with <i>Announce</i></p>");
167 case CoreHighlightSettingsPage::ChanColumn:
168 return tr("<p><b>Channel</b>: Semicolon separated list of channel/query names, leave blank "
169 "to match any name.</p>"
170 "<p><i>Example:</i><br />"
171 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
172 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
173 "except for <i>#quasseldroid</i><br />"
174 "<p>If only inverted names are specified, it will match anything except for "
175 "what's specified (implicit wildcard).</p>"
176 "<p><i>Example:</i><br />"
177 "<i>!#quassel*; !#foobar</i><br />"
178 "would match anything except for <i>#foobar</i> or any channel starting with "
179 "<i>#quassel</i></p>");
182 // This shouldn't happen
183 return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
187 void CoreHighlightSettingsPage::setupTableTooltips(
188 QWidget* enableWidget, QWidget* nameWidget, QWidget* regExWidget, QWidget* csWidget, QWidget* senderWidget, QWidget* chanWidget) const
190 // Make sure everything's valid
191 Q_ASSERT(enableWidget);
192 Q_ASSERT(nameWidget);
193 Q_ASSERT(regExWidget);
195 Q_ASSERT(senderWidget);
196 Q_ASSERT(chanWidget);
198 // Set tooltips and "What's this?" prompts
200 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
201 enableWidget->setWhatsThis(enableWidget->toolTip());
204 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
205 nameWidget->setWhatsThis(nameWidget->toolTip());
208 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
209 regExWidget->setWhatsThis(regExWidget->toolTip());
212 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
213 csWidget->setWhatsThis(csWidget->toolTip());
216 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
217 senderWidget->setWhatsThis(senderWidget->toolTip());
219 // Channel/buffer name
220 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
221 chanWidget->setWhatsThis(chanWidget->toolTip());
224 void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem* enableWidget,
225 QTableWidgetItem* nameWidget,
226 QTableWidgetItem* regExWidget,
227 QTableWidgetItem* csWidget,
228 QTableWidgetItem* senderWidget,
229 QTableWidgetItem* chanWidget) const
231 // Make sure everything's valid
232 Q_ASSERT(enableWidget);
233 Q_ASSERT(nameWidget);
234 Q_ASSERT(regExWidget);
236 Q_ASSERT(senderWidget);
237 Q_ASSERT(chanWidget);
239 // Set tooltips and "What's this?" prompts
241 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
242 enableWidget->setWhatsThis(enableWidget->toolTip());
245 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
246 nameWidget->setWhatsThis(nameWidget->toolTip());
249 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
250 regExWidget->setWhatsThis(regExWidget->toolTip());
253 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
254 csWidget->setWhatsThis(csWidget->toolTip());
257 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
258 senderWidget->setWhatsThis(senderWidget->toolTip());
260 // Channel/buffer name
261 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
262 chanWidget->setWhatsThis(chanWidget->toolTip());
265 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
267 // Assume connected state as enforced by the settings page UI
268 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
269 // Either disconnected or core supports highlights, enable highlight configuration and hide
270 // warning. Don't show the warning needlessly when disconnected.
271 ui.highlightsConfigWidget->setEnabled(true);
272 ui.coreUnsupportedWidget->setVisible(false);
275 // Core does not support highlights, show warning and disable highlight configuration
276 ui.highlightsConfigWidget->setEnabled(false);
277 ui.coreUnsupportedWidget->setVisible(true);
281 void CoreHighlightSettingsPage::clientConnected()
283 connect(Client::highlightRuleManager(), &SyncableObject::updated, this, &CoreHighlightSettingsPage::revert);
286 void CoreHighlightSettingsPage::revert()
291 setChangedState(false);
295 bool CoreHighlightSettingsPage::hasDefaults() const
300 void CoreHighlightSettingsPage::defaults()
302 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
303 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
304 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
305 ui.nicksCaseSensitive->setChecked(false);
306 emptyHighlightTable();
312 void CoreHighlightSettingsPage::addNewHighlightRow(
313 bool enable, int id, const QString& name, bool regex, bool cs, const QString& sender, const QString& chanName, bool self)
315 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
321 auto* nameItem = new QTableWidgetItem(name);
323 auto* regexItem = new QTableWidgetItem("");
325 regexItem->setCheckState(Qt::Checked);
327 regexItem->setCheckState(Qt::Unchecked);
328 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
330 auto* csItem = new QTableWidgetItem("");
332 csItem->setCheckState(Qt::Checked);
334 csItem->setCheckState(Qt::Unchecked);
335 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
337 auto* enableItem = new QTableWidgetItem("");
339 enableItem->setCheckState(Qt::Checked);
341 enableItem->setCheckState(Qt::Unchecked);
342 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
344 auto* senderItem = new QTableWidgetItem(sender);
346 auto* chanNameItem = new QTableWidgetItem(chanName);
348 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
350 int lastRow = ui.highlightTable->rowCount() - 1;
351 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
352 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
353 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
354 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
355 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
356 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
359 ui.highlightTable->setCurrentItem(nameItem);
361 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
364 void CoreHighlightSettingsPage::addNewIgnoredRow(
365 bool enable, int id, const QString& name, bool regex, bool cs, const QString& sender, const QString& chanName, bool self)
367 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
373 auto* nameItem = new QTableWidgetItem(name);
375 auto* regexItem = new QTableWidgetItem("");
377 regexItem->setCheckState(Qt::Checked);
379 regexItem->setCheckState(Qt::Unchecked);
380 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
382 auto* csItem = new QTableWidgetItem("");
384 csItem->setCheckState(Qt::Checked);
386 csItem->setCheckState(Qt::Unchecked);
387 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
389 auto* enableItem = new QTableWidgetItem("");
391 enableItem->setCheckState(Qt::Checked);
393 enableItem->setCheckState(Qt::Unchecked);
394 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
396 auto* chanNameItem = new QTableWidgetItem(chanName);
398 auto* senderItem = new QTableWidgetItem(sender);
400 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
402 int lastRow = ui.ignoredTable->rowCount() - 1;
403 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
404 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
405 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
406 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
407 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
408 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
411 ui.ignoredTable->setCurrentItem(nameItem);
413 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
416 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
418 QList<int> selectedRows;
419 QList<QTableWidgetItem*> selectedItemList = ui.highlightTable->selectedItems();
420 for (auto selectedItem : selectedItemList) {
421 selectedRows.append(selectedItem->row());
423 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
425 for (auto row : selectedRows) {
426 if (row != lastRow) {
427 ui.highlightTable->removeRow(row);
428 highlightList.removeAt(row);
434 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
436 QList<int> selectedRows;
437 QList<QTableWidgetItem*> selectedItemList = ui.ignoredTable->selectedItems();
438 for (auto selectedItem : selectedItemList) {
439 selectedRows.append(selectedItem->row());
441 std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
443 for (auto row : selectedRows) {
444 if (row != lastRow) {
445 ui.ignoredTable->removeRow(row);
446 ignoredList.removeAt(row);
452 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
454 // Only allow toggling "Case sensitive" when a nickname will be highlighted
455 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
456 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
459 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem* item)
461 int row = item->row();
462 bool selected = item->isSelected();
463 ui.highlightTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1), selected);
466 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem* item)
468 int row = item->row();
469 bool selected = item->isSelected();
470 ui.ignoredTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1), selected);
473 void CoreHighlightSettingsPage::emptyHighlightTable()
475 // ui.highlight and highlightList should have the same size, but just to make sure.
476 if (ui.highlightTable->rowCount() != highlightList.size()) {
477 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
479 while (ui.highlightTable->rowCount()) {
480 ui.highlightTable->removeRow(0);
482 highlightList.clear();
485 void CoreHighlightSettingsPage::emptyIgnoredTable()
487 // ui.highlight and highlightList should have the same size, but just to make sure.
488 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
489 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
491 while (ui.ignoredTable->rowCount()) {
492 ui.ignoredTable->removeRow(0);
497 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem* item)
499 if (item->row() + 1 > highlightList.size())
502 auto highlightRule = highlightList.value(item->row());
504 switch (item->column()) {
505 case CoreHighlightSettingsPage::EnableColumn:
506 highlightRule.setIsEnabled(item->checkState() == Qt::Checked);
508 case CoreHighlightSettingsPage::NameColumn:
509 highlightRule.setContents(item->text());
511 case CoreHighlightSettingsPage::RegExColumn:
512 highlightRule.setIsRegEx(item->checkState() == Qt::Checked);
514 case CoreHighlightSettingsPage::CsColumn:
515 highlightRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
517 case CoreHighlightSettingsPage::SenderColumn:
518 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
520 highlightRule.setSender(item->text());
522 case CoreHighlightSettingsPage::ChanColumn:
523 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
525 highlightRule.setChanName(item->text());
528 highlightList[item->row()] = highlightRule;
529 emit widgetHasChanged();
532 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem* item)
534 if (item->row() + 1 > ignoredList.size())
537 auto ignoredRule = ignoredList.value(item->row());
539 switch (item->column()) {
540 case CoreHighlightSettingsPage::EnableColumn:
541 ignoredRule.setIsEnabled(item->checkState() == Qt::Checked);
543 case CoreHighlightSettingsPage::NameColumn:
544 ignoredRule.setContents(item->text());
546 case CoreHighlightSettingsPage::RegExColumn:
547 ignoredRule.setIsRegEx(item->checkState() == Qt::Checked);
549 case CoreHighlightSettingsPage::CsColumn:
550 ignoredRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
552 case CoreHighlightSettingsPage::SenderColumn:
553 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
555 ignoredRule.setSender(item->text());
557 case CoreHighlightSettingsPage::ChanColumn:
558 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
560 ignoredRule.setChanName(item->text());
563 ignoredList[item->row()] = ignoredRule;
564 emit widgetHasChanged();
567 void CoreHighlightSettingsPage::load()
569 emptyHighlightTable();
572 auto ruleManager = Client::highlightRuleManager();
574 for (auto& rule : ruleManager->highlightRuleList()) {
575 if (rule.isInverse()) {
576 addNewIgnoredRow(rule.isEnabled(),
580 rule.isCaseSensitive(),
585 addNewHighlightRow(rule.isEnabled(),
589 rule.isCaseSensitive(),
595 int highlightNickType = ruleManager->highlightNick();
596 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
597 // Trigger the initial update of nicksCaseSensitive being enabled or not
598 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
599 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
601 setChangedState(false);
609 void CoreHighlightSettingsPage::save()
617 auto ruleManager = Client::highlightRuleManager();
618 if (ruleManager == nullptr)
621 auto clonedManager = HighlightRuleManager();
622 clonedManager.fromVariantMap(ruleManager->toVariantMap());
623 clonedManager.clear();
625 for (auto& rule : highlightList) {
626 clonedManager.addHighlightRule(rule.id(),
629 rule.isCaseSensitive(),
636 for (auto& rule : ignoredList) {
637 clonedManager.addHighlightRule(rule.id(),
640 rule.isCaseSensitive(),
647 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
649 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
650 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
652 ruleManager->requestUpdate(clonedManager.toVariantMap());
653 setChangedState(false);
657 int CoreHighlightSettingsPage::nextId()
660 for (int i = 0; i < highlightList.count(); i++) {
661 int id = highlightList[i].id();
666 for (int i = 0; i < ignoredList.count(); i++) {
667 int id = ignoredList[i].id();
675 void CoreHighlightSettingsPage::widgetHasChanged()
677 setChangedState(true);
680 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
682 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
683 // spaces to non-breaking
684 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
686 const QString remoteHighlightsMsgText = QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>")
687 .arg(tr("Your Quassel core is too old to support remote highlights"),
688 tr("You need a Quassel core v0.13.0 or newer to configure remote "
690 tr("You can still configure highlights for this device only in "
692 .arg(localHighlightsName));
694 QMessageBox::warning(this, tr("Remote Highlights unsupported"), remoteHighlightsMsgText);
697 void CoreHighlightSettingsPage::importRules()
699 NotificationSettings notificationSettings;
701 const auto localHighlightList = notificationSettings.highlightList();
703 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
704 // forcing all spaces to non-breaking
705 QString localHighlightsName;
706 if (Quassel::runMode() == Quassel::Monolithic) {
707 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
710 localHighlightsName = tr("Local Highlights").replace(" ", " ");
713 if (localHighlightList.count() == 0) {
714 // No highlight rules exist to import, do nothing
715 QMessageBox::information(this, tr("No highlights to import"), tr("No highlight rules in <i>%1</i>.").arg(localHighlightsName));
719 int ret = QMessageBox::question(this,
720 tr("Import highlights?"),
721 tr("Import all highlight rules from <i>%1</i>?").arg(localHighlightsName),
722 QMessageBox::Yes | QMessageBox::No,
725 if (ret != QMessageBox::Yes) {
726 // Only two options, Yes or No, return if not Yes
731 // Save existing changes first to avoid overwriting them
735 auto clonedManager = HighlightRuleManager();
736 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
738 for (const auto& variant : notificationSettings.highlightList()) {
739 auto highlightRule = variant.toMap();
741 clonedManager.addHighlightRule(clonedManager.nextId(),
742 highlightRule["Name"].toString(),
743 highlightRule["RegEx"].toBool(),
744 highlightRule["CS"].toBool(),
745 highlightRule["Enable"].toBool(),
748 highlightRule["Channel"].toString());
751 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
752 setChangedState(false);
755 // Give a heads-up that all succeeded
756 QMessageBox::information(this,
757 tr("Imported highlights"),
758 tr("%1 highlight rules successfully imported.").arg(QString::number(localHighlightList.count())));
761 bool CoreHighlightSettingsPage::isSelectable() const
763 return Client::isConnected();
764 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
765 // a friendly error message.