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"
30 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent)
31 : SettingsPage(tr("Interface"),
32 // In Monolithic mode, local highlights are replaced by remote highlights
33 Quassel::runMode() == Quassel::Monolithic ?
34 tr("Highlights") : tr("Remote Highlights"),
39 setupRuleTable(ui.highlightTable);
40 setupRuleTable(ui.ignoredTable);
42 ui.highlightNicksComboBox->addItem(tr("All Nicks from Identity"), QVariant(HighlightRuleManager::AllNicks));
43 ui.highlightNicksComboBox->addItem(tr("Current Nick"), QVariant(HighlightRuleManager::CurrentNick));
44 ui.highlightNicksComboBox->addItem(tr("None"), QVariant(HighlightRuleManager::NoNick));
46 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
47 connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
49 connect(ui.highlightAdd, SIGNAL(clicked(bool)), this, SLOT(addNewHighlightRow()));
50 connect(ui.highlightRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedHighlightRows()));
51 connect(ui.highlightImport, SIGNAL(clicked(bool)), this, SLOT(importRules()));
53 connect(ui.ignoredAdd, SIGNAL(clicked(bool)), this, SLOT(addNewIgnoredRow()));
54 connect(ui.ignoredRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedIgnoredRows()));
56 // TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
57 connect(ui.highlightTable,
58 SIGNAL(itemClicked(QTableWidgetItem * )),
60 SLOT(selectHighlightRow(QTableWidgetItem * )));
61 connect(ui.ignoredTable,
62 SIGNAL(itemClicked(QTableWidgetItem * )),
64 SLOT(selectIgnoredRow(QTableWidgetItem * )));
66 // Update the "Case sensitive" checkbox
67 connect(ui.highlightNicksComboBox,
68 SIGNAL(currentIndexChanged(int)),
70 SLOT(highlightNicksChanged(int)));
72 connect(ui.highlightNicksComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
73 connect(ui.nicksCaseSensitive, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
75 connect(ui.highlightAdd, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
76 connect(ui.highlightRemove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
78 connect(ui.ignoredAdd, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
79 connect(ui.ignoredRemove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
81 connect(ui.highlightTable,
82 SIGNAL(itemChanged(QTableWidgetItem * )),
84 SLOT(highlightTableChanged(QTableWidgetItem * )));
86 connect(ui.ignoredTable,
87 SIGNAL(itemChanged(QTableWidgetItem * )),
89 SLOT(ignoredTableChanged(QTableWidgetItem * )));
91 connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected()));
94 ui.coreUnsupportedIcon->setPixmap(icon::get("dialog-warning").pixmap(16));
96 // Set up client/monolithic remote highlights information
97 if (Quassel::runMode() == Quassel::Monolithic) {
98 // We're running in Monolithic mode, local highlights are considered legacy
99 ui.highlightImport->setText(tr("Import Legacy"));
100 ui.highlightImport->setToolTip(tr("Import highlight rules configured in <i>%1</i>.")
101 .arg(tr("Legacy Highlights").replace(" ", " ")));
102 // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing
103 // all spaces to be non-breaking
105 // We're running in client/split mode, local highlights are distinguished from remote
106 ui.highlightImport->setText(tr("Import Local"));
107 ui.highlightImport->setToolTip(tr("Import highlight rules configured in <i>%1</i>.")
108 .arg(tr("Local Highlights").replace(" ", " ")));
109 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing
110 // all spaces to be non-breaking
115 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
117 updateCoreSupportStatus(state);
127 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const
129 table->verticalHeader()->hide();
130 table->setShowGrid(false);
132 setupTableTooltips(table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn),
133 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn),
134 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn),
135 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn),
136 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn),
137 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn));
139 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
140 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
141 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
142 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
143 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
144 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
145 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
147 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
148 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
149 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
150 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
151 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
152 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
157 QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
159 switch (tableColumn) {
160 case CoreHighlightSettingsPage::EnableColumn:
161 return tr("Enable/disable this rule");
163 case CoreHighlightSettingsPage::NameColumn:
164 return tr("Phrase to match, leave blank to match any message");
166 case CoreHighlightSettingsPage::RegExColumn:
167 return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
168 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
171 case CoreHighlightSettingsPage::CsColumn:
172 return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
173 "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
175 case CoreHighlightSettingsPage::SenderColumn:
176 return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
177 "leave blank to match any nickname.</p>"
178 "<p><i>Example:</i><br />"
179 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
180 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
181 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
182 "<p>If only inverted names are specified, it will match anything except for "
183 "what's specified (implicit wildcard).</p>"
184 "<p><i>Example:</i><br />"
185 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
186 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
187 "any nickname starting with <i>Announce</i></p>");
189 case CoreHighlightSettingsPage::ChanColumn:
190 return tr("<p><b>Channel</b>: Semicolon separated list of channel/query names, leave blank "
191 "to match any name.</p>"
192 "<p><i>Example:</i><br />"
193 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
194 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
195 "except for <i>#quasseldroid</i><br />"
196 "<p>If only inverted names are specified, it will match anything except for "
197 "what's specified (implicit wildcard).</p>"
198 "<p><i>Example:</i><br />"
199 "<i>!#quassel*; !#foobar</i><br />"
200 "would match anything except for <i>#foobar</i> or any channel starting with "
201 "<i>#quassel</i></p>");
204 // This shouldn't happen
205 return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
210 void CoreHighlightSettingsPage::setupTableTooltips(QWidget *enableWidget, QWidget *nameWidget,
211 QWidget *regExWidget, QWidget *csWidget,
212 QWidget *senderWidget, QWidget *chanWidget) const
214 // Make sure everything's valid
215 Q_ASSERT(enableWidget);
216 Q_ASSERT(nameWidget);
217 Q_ASSERT(regExWidget);
219 Q_ASSERT(senderWidget);
220 Q_ASSERT(chanWidget);
222 // Set tooltips and "What's this?" prompts
224 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
225 enableWidget->setWhatsThis(enableWidget->toolTip());
228 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
229 nameWidget->setWhatsThis(nameWidget->toolTip());
232 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
233 regExWidget->setWhatsThis(regExWidget->toolTip());
236 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
237 csWidget->setWhatsThis(csWidget->toolTip());
240 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
241 senderWidget->setWhatsThis(senderWidget->toolTip());
243 // Channel/buffer name
244 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
245 chanWidget->setWhatsThis(chanWidget->toolTip());
249 void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem *enableWidget,
250 QTableWidgetItem *nameWidget,
251 QTableWidgetItem *regExWidget,
252 QTableWidgetItem *csWidget,
253 QTableWidgetItem *senderWidget,
254 QTableWidgetItem *chanWidget) const
256 // Make sure everything's valid
257 Q_ASSERT(enableWidget);
258 Q_ASSERT(nameWidget);
259 Q_ASSERT(regExWidget);
261 Q_ASSERT(senderWidget);
262 Q_ASSERT(chanWidget);
264 // Set tooltips and "What's this?" prompts
266 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
267 enableWidget->setWhatsThis(enableWidget->toolTip());
270 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
271 nameWidget->setWhatsThis(nameWidget->toolTip());
274 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
275 regExWidget->setWhatsThis(regExWidget->toolTip());
278 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
279 csWidget->setWhatsThis(csWidget->toolTip());
282 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
283 senderWidget->setWhatsThis(senderWidget->toolTip());
285 // Channel/buffer name
286 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
287 chanWidget->setWhatsThis(chanWidget->toolTip());
291 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
293 // Assume connected state as enforced by the settings page UI
294 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
295 // Either disconnected or core supports highlights, enable highlight configuration and hide
296 // warning. Don't show the warning needlessly when disconnected.
297 ui.highlightsConfigWidget->setEnabled(true);
298 ui.coreUnsupportedWidget->setVisible(false);
300 // Core does not support highlights, show warning and disable highlight configuration
301 ui.highlightsConfigWidget->setEnabled(false);
302 ui.coreUnsupportedWidget->setVisible(true);
307 void CoreHighlightSettingsPage::clientConnected()
309 connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
313 void CoreHighlightSettingsPage::revert()
318 setChangedState(false);
323 bool CoreHighlightSettingsPage::hasDefaults() const
329 void CoreHighlightSettingsPage::defaults()
331 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
332 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
333 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
334 ui.nicksCaseSensitive->setChecked(false);
335 emptyHighlightTable();
342 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, int id, const QString &name, bool regex, bool cs,
343 const QString &sender, const QString &chanName, bool self)
345 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
351 auto *nameItem = new QTableWidgetItem(name);
353 auto *regexItem = new QTableWidgetItem("");
355 regexItem->setCheckState(Qt::Checked);
357 regexItem->setCheckState(Qt::Unchecked);
358 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
360 auto *csItem = new QTableWidgetItem("");
362 csItem->setCheckState(Qt::Checked);
364 csItem->setCheckState(Qt::Unchecked);
365 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
367 auto *enableItem = new QTableWidgetItem("");
369 enableItem->setCheckState(Qt::Checked);
371 enableItem->setCheckState(Qt::Unchecked);
372 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
374 auto *senderItem = new QTableWidgetItem(sender);
376 auto *chanNameItem = new QTableWidgetItem(chanName);
378 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
380 int lastRow = ui.highlightTable->rowCount() - 1;
381 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
382 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
383 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
384 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
385 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
386 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
389 ui.highlightTable->setCurrentItem(nameItem);
391 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
395 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, int id, const QString &name, bool regex, bool cs,
396 const QString &sender, const QString &chanName, bool self)
398 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
404 auto *nameItem = new QTableWidgetItem(name);
406 auto *regexItem = new QTableWidgetItem("");
408 regexItem->setCheckState(Qt::Checked);
410 regexItem->setCheckState(Qt::Unchecked);
411 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
413 auto *csItem = new QTableWidgetItem("");
415 csItem->setCheckState(Qt::Checked);
417 csItem->setCheckState(Qt::Unchecked);
418 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
420 auto *enableItem = new QTableWidgetItem("");
422 enableItem->setCheckState(Qt::Checked);
424 enableItem->setCheckState(Qt::Unchecked);
425 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
427 auto *chanNameItem = new QTableWidgetItem(chanName);
429 auto *senderItem = new QTableWidgetItem(sender);
431 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
433 int lastRow = ui.ignoredTable->rowCount() - 1;
434 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
435 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
436 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
437 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
438 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
439 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
442 ui.ignoredTable->setCurrentItem(nameItem);
444 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
448 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
450 QList<int> selectedRows;
451 QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
452 for (auto selectedItem : selectedItemList) {
453 selectedRows.append(selectedItem->row());
455 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
457 for (auto row : selectedRows) {
458 if (row != lastRow) {
459 ui.highlightTable->removeRow(row);
460 highlightList.removeAt(row);
467 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
469 QList<int> selectedRows;
470 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
471 for (auto selectedItem : selectedItemList) {
472 selectedRows.append(selectedItem->row());
474 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
476 for (auto row : selectedRows) {
477 if (row != lastRow) {
478 ui.ignoredTable->removeRow(row);
479 ignoredList.removeAt(row);
486 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
488 // Only allow toggling "Case sensitive" when a nickname will be highlighted
489 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
490 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
494 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
496 int row = item->row();
497 bool selected = item->isSelected();
499 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
504 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
506 int row = item->row();
507 bool selected = item->isSelected();
509 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
514 void CoreHighlightSettingsPage::emptyHighlightTable()
516 // ui.highlight and highlightList should have the same size, but just to make sure.
517 if (ui.highlightTable->rowCount() != highlightList.size()) {
518 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
520 while (ui.highlightTable->rowCount()) {
521 ui.highlightTable->removeRow(0);
523 highlightList.clear();
527 void CoreHighlightSettingsPage::emptyIgnoredTable()
529 // ui.highlight and highlightList should have the same size, but just to make sure.
530 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
531 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
533 while (ui.ignoredTable->rowCount()) {
534 ui.ignoredTable->removeRow(0);
540 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
542 if (item->row() + 1 > highlightList.size())
545 auto highlightRule = highlightList.value(item->row());
548 switch (item->column()) {
549 case CoreHighlightSettingsPage::EnableColumn:
550 highlightRule.isEnabled = (item->checkState() == Qt::Checked);
552 case CoreHighlightSettingsPage::NameColumn:
553 highlightRule.name = item->text();
555 case CoreHighlightSettingsPage::RegExColumn:
556 highlightRule.isRegEx = (item->checkState() == Qt::Checked);
558 case CoreHighlightSettingsPage::CsColumn:
559 highlightRule.isCaseSensitive = (item->checkState() == Qt::Checked);
561 case CoreHighlightSettingsPage::SenderColumn:
562 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
564 highlightRule.sender = item->text();
566 case CoreHighlightSettingsPage::ChanColumn:
567 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
569 highlightRule.chanName = item->text();
572 highlightList[item->row()] = highlightRule;
573 emit widgetHasChanged();
577 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
579 if (item->row() + 1 > ignoredList.size())
582 auto ignoredRule = ignoredList.value(item->row());
585 switch (item->column()) {
586 case CoreHighlightSettingsPage::EnableColumn:
587 ignoredRule.isEnabled = (item->checkState() == Qt::Checked);
589 case CoreHighlightSettingsPage::NameColumn:
590 ignoredRule.name = item->text();
592 case CoreHighlightSettingsPage::RegExColumn:
593 ignoredRule.isRegEx = (item->checkState() == Qt::Checked);
595 case CoreHighlightSettingsPage::CsColumn:
596 ignoredRule.isCaseSensitive = (item->checkState() == Qt::Checked);
598 case CoreHighlightSettingsPage::SenderColumn:
599 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
601 ignoredRule.sender = item->text();
603 case CoreHighlightSettingsPage::ChanColumn:
604 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
606 ignoredRule.chanName = item->text();
609 ignoredList[item->row()] = ignoredRule;
610 emit widgetHasChanged();
614 void CoreHighlightSettingsPage::load()
616 emptyHighlightTable();
619 auto ruleManager = Client::highlightRuleManager();
621 for (auto &rule : ruleManager->highlightRuleList()) {
622 if (rule.isInverse) {
623 addNewIgnoredRow(rule.isEnabled,
627 rule.isCaseSensitive,
632 addNewHighlightRow(rule.isEnabled, rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender,
637 int highlightNickType = ruleManager->highlightNick();
638 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
639 // Trigger the initial update of nicksCaseSensitive being enabled or not
640 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
641 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
643 setChangedState(false);
651 void CoreHighlightSettingsPage::save()
659 auto ruleManager = Client::highlightRuleManager();
660 if (ruleManager == nullptr)
663 auto clonedManager = HighlightRuleManager();
664 clonedManager.fromVariantMap(ruleManager->toVariantMap());
665 clonedManager.clear();
667 for (auto &rule : highlightList) {
668 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false,
669 rule.sender, rule.chanName);
672 for (auto &rule : ignoredList) {
673 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true,
674 rule.sender, rule.chanName);
677 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
679 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
680 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
682 ruleManager->requestUpdate(clonedManager.toVariantMap());
683 setChangedState(false);
688 int CoreHighlightSettingsPage::nextId()
691 for (int i = 0; i < highlightList.count(); i++) {
692 int id = highlightList[i].id;
697 for (int i = 0; i < ignoredList.count(); i++) {
698 int id = ignoredList[i].id;
707 void CoreHighlightSettingsPage::widgetHasChanged()
709 setChangedState(true);
713 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
715 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
716 // spaces to non-breaking
717 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
719 const QString remoteHighlightsMsgText =
720 QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>"
721 ).arg(tr("Your Quassel core is too old to support remote highlights"),
722 tr("You need a Quassel core v0.13.0 or newer to configure remote "
724 tr("You can still configure highlights for this device only in "
725 "<i>%1</i>.").arg(localHighlightsName));
727 QMessageBox::warning(this,
728 tr("Remote Highlights unsupported"),
729 remoteHighlightsMsgText);
733 void CoreHighlightSettingsPage::importRules()
735 NotificationSettings notificationSettings;
737 const auto localHighlightList = notificationSettings.highlightList();
739 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
740 // forcing all spaces to non-breaking
741 QString localHighlightsName;
742 if (Quassel::runMode() == Quassel::Monolithic) {
743 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
745 localHighlightsName = tr("Local Highlights").replace(" ", " ");
748 if (localHighlightList.count() == 0) {
749 // No highlight rules exist to import, do nothing
750 QMessageBox::information(this,
751 tr("No highlights to import"),
752 tr("No highlight rules in <i>%1</i>."
753 ).arg(localHighlightsName));
757 int ret = QMessageBox::question(this,
758 tr("Import highlights?"),
759 tr("Import all highlight rules from <i>%1</i>?"
760 ).arg(localHighlightsName),
761 QMessageBox::Yes|QMessageBox::No,
764 if (ret != QMessageBox::Yes) {
765 // Only two options, Yes or No, return if not Yes
770 // Save existing changes first to avoid overwriting them
774 auto clonedManager = HighlightRuleManager();
775 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
777 for (const auto &variant : notificationSettings.highlightList()) {
778 auto highlightRule = variant.toMap();
780 clonedManager.addHighlightRule(
781 clonedManager.nextId(),
782 highlightRule["Name"].toString(),
783 highlightRule["RegEx"].toBool(),
784 highlightRule["CS"].toBool(),
785 highlightRule["Enable"].toBool(),
788 highlightRule["Channel"].toString()
792 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
793 setChangedState(false);
796 // Give a heads-up that all succeeded
797 QMessageBox::information(this,
798 tr("Imported highlights"),
799 tr("%1 highlight rules successfully imported."
800 ).arg(QString::number(localHighlightList.count())));
804 bool CoreHighlightSettingsPage::isSelectable() const
806 return Client::isConnected();
807 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
808 // a friendly error message.