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"
31 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent)
32 : SettingsPage(tr("Interface"),
33 // In Monolithic mode, local highlights are replaced by remote highlights
34 Quassel::runMode() == Quassel::Monolithic ?
35 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, selectOverload<int>(&QComboBox::currentIndexChanged), this, &CoreHighlightSettingsPage::highlightNicksChanged);
63 connect(ui.highlightNicksComboBox, selectOverload<int>(&QComboBox::currentIndexChanged), this, &CoreHighlightSettingsPage::widgetHasChanged);
64 connect(ui.nicksCaseSensitive, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
66 connect(ui.highlightAdd, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
67 connect(ui.highlightRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
69 connect(ui.ignoredAdd, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
70 connect(ui.ignoredRemove, &QAbstractButton::clicked, this, &CoreHighlightSettingsPage::widgetHasChanged);
72 connect(ui.highlightTable,
73 &QTableWidget::itemChanged,
75 &CoreHighlightSettingsPage::highlightTableChanged);
77 connect(ui.ignoredTable,
78 &QTableWidget::itemChanged,
80 &CoreHighlightSettingsPage::ignoredTableChanged);
82 connect(Client::instance(), &Client::connected, this, &CoreHighlightSettingsPage::clientConnected);
85 ui.coreUnsupportedIcon->setPixmap(icon::get("dialog-warning").pixmap(16));
87 // Set up client/monolithic remote highlights information
88 if (Quassel::runMode() == Quassel::Monolithic) {
89 // We're running in Monolithic mode, local highlights are considered legacy
90 ui.highlightImport->setText(tr("Import Legacy"));
91 ui.highlightImport->setToolTip(tr("Import highlight rules configured in <i>%1</i>.")
92 .arg(tr("Legacy Highlights").replace(" ", " ")));
93 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing
94 // 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(tr("Import highlight rules configured in <i>%1</i>.")
99 .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
106 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
108 updateCoreSupportStatus(state);
118 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const
120 table->verticalHeader()->hide();
121 table->setShowGrid(false);
123 setupTableTooltips(table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn),
124 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn),
125 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn),
126 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn),
127 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn),
128 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn));
130 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
131 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
132 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
133 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
134 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
135 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
139 QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
141 switch (tableColumn) {
142 case CoreHighlightSettingsPage::EnableColumn:
143 return tr("Enable/disable this rule");
145 case CoreHighlightSettingsPage::NameColumn:
146 return tr("Phrase to match, leave blank to match any message");
148 case CoreHighlightSettingsPage::RegExColumn:
149 return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
150 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
153 case CoreHighlightSettingsPage::CsColumn:
154 return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
155 "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
157 case CoreHighlightSettingsPage::SenderColumn:
158 return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
159 "leave blank to match any nickname.</p>"
160 "<p><i>Example:</i><br />"
161 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
162 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
163 "any nickname starting with <i>Carol</i> except for <i>Caroline</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>!Announce*!*; !Wheatley!aperture@*</i><br />"
168 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
169 "any nickname starting with <i>Announce</i></p>");
171 case CoreHighlightSettingsPage::ChanColumn:
172 return tr("<p><b>Channel</b>: Semicolon separated list of channel/query names, leave blank "
173 "to match any name.</p>"
174 "<p><i>Example:</i><br />"
175 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
176 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
177 "except for <i>#quasseldroid</i><br />"
178 "<p>If only inverted names are specified, it will match anything except for "
179 "what's specified (implicit wildcard).</p>"
180 "<p><i>Example:</i><br />"
181 "<i>!#quassel*; !#foobar</i><br />"
182 "would match anything except for <i>#foobar</i> or any channel starting with "
183 "<i>#quassel</i></p>");
186 // This shouldn't happen
187 return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
192 void CoreHighlightSettingsPage::setupTableTooltips(QWidget *enableWidget, QWidget *nameWidget,
193 QWidget *regExWidget, QWidget *csWidget,
194 QWidget *senderWidget, QWidget *chanWidget) const
196 // Make sure everything's valid
197 Q_ASSERT(enableWidget);
198 Q_ASSERT(nameWidget);
199 Q_ASSERT(regExWidget);
201 Q_ASSERT(senderWidget);
202 Q_ASSERT(chanWidget);
204 // Set tooltips and "What's this?" prompts
206 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
207 enableWidget->setWhatsThis(enableWidget->toolTip());
210 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
211 nameWidget->setWhatsThis(nameWidget->toolTip());
214 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
215 regExWidget->setWhatsThis(regExWidget->toolTip());
218 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
219 csWidget->setWhatsThis(csWidget->toolTip());
222 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
223 senderWidget->setWhatsThis(senderWidget->toolTip());
225 // Channel/buffer name
226 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
227 chanWidget->setWhatsThis(chanWidget->toolTip());
231 void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem *enableWidget,
232 QTableWidgetItem *nameWidget,
233 QTableWidgetItem *regExWidget,
234 QTableWidgetItem *csWidget,
235 QTableWidgetItem *senderWidget,
236 QTableWidgetItem *chanWidget) const
238 // Make sure everything's valid
239 Q_ASSERT(enableWidget);
240 Q_ASSERT(nameWidget);
241 Q_ASSERT(regExWidget);
243 Q_ASSERT(senderWidget);
244 Q_ASSERT(chanWidget);
246 // Set tooltips and "What's this?" prompts
248 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
249 enableWidget->setWhatsThis(enableWidget->toolTip());
252 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
253 nameWidget->setWhatsThis(nameWidget->toolTip());
256 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
257 regExWidget->setWhatsThis(regExWidget->toolTip());
260 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
261 csWidget->setWhatsThis(csWidget->toolTip());
264 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
265 senderWidget->setWhatsThis(senderWidget->toolTip());
267 // Channel/buffer name
268 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
269 chanWidget->setWhatsThis(chanWidget->toolTip());
273 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
275 // Assume connected state as enforced by the settings page UI
276 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
277 // Either disconnected or core supports highlights, enable highlight configuration and hide
278 // warning. Don't show the warning needlessly when disconnected.
279 ui.highlightsConfigWidget->setEnabled(true);
280 ui.coreUnsupportedWidget->setVisible(false);
282 // Core does not support highlights, show warning and disable highlight configuration
283 ui.highlightsConfigWidget->setEnabled(false);
284 ui.coreUnsupportedWidget->setVisible(true);
289 void CoreHighlightSettingsPage::clientConnected()
291 connect(Client::highlightRuleManager(), &SyncableObject::updated, this, &CoreHighlightSettingsPage::revert);
295 void CoreHighlightSettingsPage::revert()
300 setChangedState(false);
305 bool CoreHighlightSettingsPage::hasDefaults() const
311 void CoreHighlightSettingsPage::defaults()
313 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
314 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
315 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
316 ui.nicksCaseSensitive->setChecked(false);
317 emptyHighlightTable();
324 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, int id, const QString &name, bool regex, bool cs,
325 const QString &sender, const QString &chanName, bool self)
327 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
333 auto *nameItem = new QTableWidgetItem(name);
335 auto *regexItem = new QTableWidgetItem("");
337 regexItem->setCheckState(Qt::Checked);
339 regexItem->setCheckState(Qt::Unchecked);
340 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
342 auto *csItem = new QTableWidgetItem("");
344 csItem->setCheckState(Qt::Checked);
346 csItem->setCheckState(Qt::Unchecked);
347 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
349 auto *enableItem = new QTableWidgetItem("");
351 enableItem->setCheckState(Qt::Checked);
353 enableItem->setCheckState(Qt::Unchecked);
354 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
356 auto *senderItem = new QTableWidgetItem(sender);
358 auto *chanNameItem = new QTableWidgetItem(chanName);
360 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
362 int lastRow = ui.highlightTable->rowCount() - 1;
363 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
364 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
365 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
366 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
367 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
368 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
371 ui.highlightTable->setCurrentItem(nameItem);
373 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
377 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, int id, const QString &name, bool regex, bool cs,
378 const QString &sender, const QString &chanName, bool self)
380 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
386 auto *nameItem = new QTableWidgetItem(name);
388 auto *regexItem = new QTableWidgetItem("");
390 regexItem->setCheckState(Qt::Checked);
392 regexItem->setCheckState(Qt::Unchecked);
393 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
395 auto *csItem = new QTableWidgetItem("");
397 csItem->setCheckState(Qt::Checked);
399 csItem->setCheckState(Qt::Unchecked);
400 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
402 auto *enableItem = new QTableWidgetItem("");
404 enableItem->setCheckState(Qt::Checked);
406 enableItem->setCheckState(Qt::Unchecked);
407 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
409 auto *chanNameItem = new QTableWidgetItem(chanName);
411 auto *senderItem = new QTableWidgetItem(sender);
413 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
415 int lastRow = ui.ignoredTable->rowCount() - 1;
416 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
417 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
418 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
419 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
420 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
421 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
424 ui.ignoredTable->setCurrentItem(nameItem);
426 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
430 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
432 QList<int> selectedRows;
433 QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
434 for (auto selectedItem : selectedItemList) {
435 selectedRows.append(selectedItem->row());
437 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
439 for (auto row : selectedRows) {
440 if (row != lastRow) {
441 ui.highlightTable->removeRow(row);
442 highlightList.removeAt(row);
449 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
451 QList<int> selectedRows;
452 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
453 for (auto selectedItem : selectedItemList) {
454 selectedRows.append(selectedItem->row());
456 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
458 for (auto row : selectedRows) {
459 if (row != lastRow) {
460 ui.ignoredTable->removeRow(row);
461 ignoredList.removeAt(row);
468 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
470 // Only allow toggling "Case sensitive" when a nickname will be highlighted
471 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
472 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
476 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
478 int row = item->row();
479 bool selected = item->isSelected();
481 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
486 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
488 int row = item->row();
489 bool selected = item->isSelected();
491 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
496 void CoreHighlightSettingsPage::emptyHighlightTable()
498 // ui.highlight and highlightList should have the same size, but just to make sure.
499 if (ui.highlightTable->rowCount() != highlightList.size()) {
500 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
502 while (ui.highlightTable->rowCount()) {
503 ui.highlightTable->removeRow(0);
505 highlightList.clear();
509 void CoreHighlightSettingsPage::emptyIgnoredTable()
511 // ui.highlight and highlightList should have the same size, but just to make sure.
512 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
513 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
515 while (ui.ignoredTable->rowCount()) {
516 ui.ignoredTable->removeRow(0);
522 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
524 if (item->row() + 1 > highlightList.size())
527 auto highlightRule = highlightList.value(item->row());
530 switch (item->column()) {
531 case CoreHighlightSettingsPage::EnableColumn:
532 highlightRule.setIsEnabled(item->checkState() == Qt::Checked);
534 case CoreHighlightSettingsPage::NameColumn:
535 highlightRule.setContents(item->text());
537 case CoreHighlightSettingsPage::RegExColumn:
538 highlightRule.setIsRegEx(item->checkState() == Qt::Checked);
540 case CoreHighlightSettingsPage::CsColumn:
541 highlightRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
543 case CoreHighlightSettingsPage::SenderColumn:
544 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
546 highlightRule.setSender(item->text());
548 case CoreHighlightSettingsPage::ChanColumn:
549 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
551 highlightRule.setChanName(item->text());
554 highlightList[item->row()] = highlightRule;
555 emit widgetHasChanged();
559 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
561 if (item->row() + 1 > ignoredList.size())
564 auto ignoredRule = ignoredList.value(item->row());
567 switch (item->column()) {
568 case CoreHighlightSettingsPage::EnableColumn:
569 ignoredRule.setIsEnabled(item->checkState() == Qt::Checked);
571 case CoreHighlightSettingsPage::NameColumn:
572 ignoredRule.setContents(item->text());
574 case CoreHighlightSettingsPage::RegExColumn:
575 ignoredRule.setIsRegEx(item->checkState() == Qt::Checked);
577 case CoreHighlightSettingsPage::CsColumn:
578 ignoredRule.setIsCaseSensitive(item->checkState() == Qt::Checked);
580 case CoreHighlightSettingsPage::SenderColumn:
581 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
583 ignoredRule.setSender(item->text());
585 case CoreHighlightSettingsPage::ChanColumn:
586 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
588 ignoredRule.setChanName(item->text());
591 ignoredList[item->row()] = ignoredRule;
592 emit widgetHasChanged();
596 void CoreHighlightSettingsPage::load()
598 emptyHighlightTable();
601 auto ruleManager = Client::highlightRuleManager();
603 for (auto &rule : ruleManager->highlightRuleList()) {
604 if (rule.isInverse()) {
605 addNewIgnoredRow(rule.isEnabled(), rule.id(), rule.contents(), rule.isRegEx(),
606 rule.isCaseSensitive(), rule.sender(), rule.chanName());
609 addNewHighlightRow(rule.isEnabled(), rule.id(), rule.contents(), rule.isRegEx(),
610 rule.isCaseSensitive(), rule.sender(), rule.chanName());
614 int highlightNickType = ruleManager->highlightNick();
615 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
616 // Trigger the initial update of nicksCaseSensitive being enabled or not
617 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
618 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
620 setChangedState(false);
628 void CoreHighlightSettingsPage::save()
636 auto ruleManager = Client::highlightRuleManager();
637 if (ruleManager == nullptr)
640 auto clonedManager = HighlightRuleManager();
641 clonedManager.fromVariantMap(ruleManager->toVariantMap());
642 clonedManager.clear();
644 for (auto &rule : highlightList) {
645 clonedManager.addHighlightRule(rule.id(), rule.contents(), rule.isRegEx(),
646 rule.isCaseSensitive(), rule.isEnabled(), false,
647 rule.sender(), rule.chanName());
650 for (auto &rule : ignoredList) {
651 clonedManager.addHighlightRule(rule.id(), rule.contents(), rule.isRegEx(),
652 rule.isCaseSensitive (), rule.isEnabled(), true,
653 rule.sender(), rule.chanName());
656 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
658 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
659 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
661 ruleManager->requestUpdate(clonedManager.toVariantMap());
662 setChangedState(false);
667 int CoreHighlightSettingsPage::nextId()
670 for (int i = 0; i < highlightList.count(); i++) {
671 int id = highlightList[i].id();
676 for (int i = 0; i < ignoredList.count(); i++) {
677 int id = ignoredList[i].id();
686 void CoreHighlightSettingsPage::widgetHasChanged()
688 setChangedState(true);
692 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
694 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
695 // spaces to non-breaking
696 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
698 const QString remoteHighlightsMsgText =
699 QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>"
700 ).arg(tr("Your Quassel core is too old to support remote highlights"),
701 tr("You need a Quassel core v0.13.0 or newer to configure remote "
703 tr("You can still configure highlights for this device only in "
704 "<i>%1</i>.").arg(localHighlightsName));
706 QMessageBox::warning(this,
707 tr("Remote Highlights unsupported"),
708 remoteHighlightsMsgText);
712 void CoreHighlightSettingsPage::importRules()
714 NotificationSettings notificationSettings;
716 const auto localHighlightList = notificationSettings.highlightList();
718 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
719 // forcing all spaces to non-breaking
720 QString localHighlightsName;
721 if (Quassel::runMode() == Quassel::Monolithic) {
722 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
724 localHighlightsName = tr("Local Highlights").replace(" ", " ");
727 if (localHighlightList.count() == 0) {
728 // No highlight rules exist to import, do nothing
729 QMessageBox::information(this,
730 tr("No highlights to import"),
731 tr("No highlight rules in <i>%1</i>."
732 ).arg(localHighlightsName));
736 int ret = QMessageBox::question(this,
737 tr("Import highlights?"),
738 tr("Import all highlight rules from <i>%1</i>?"
739 ).arg(localHighlightsName),
740 QMessageBox::Yes|QMessageBox::No,
743 if (ret != QMessageBox::Yes) {
744 // Only two options, Yes or No, return if not Yes
749 // Save existing changes first to avoid overwriting them
753 auto clonedManager = HighlightRuleManager();
754 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
756 for (const auto &variant : notificationSettings.highlightList()) {
757 auto highlightRule = variant.toMap();
759 clonedManager.addHighlightRule(
760 clonedManager.nextId(),
761 highlightRule["Name"].toString(),
762 highlightRule["RegEx"].toBool(),
763 highlightRule["CS"].toBool(),
764 highlightRule["Enable"].toBool(),
767 highlightRule["Channel"].toString()
771 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
772 setChangedState(false);
775 // Give a heads-up that all succeeded
776 QMessageBox::information(this,
777 tr("Imported highlights"),
778 tr("%1 highlight rules successfully imported."
779 ).arg(QString::number(localHighlightList.count())));
783 bool CoreHighlightSettingsPage::isSelectable() const
785 return Client::isConnected();
786 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
787 // a friendly error message.