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::ChanColumn, QHeaderView::ResizeToContents);
146 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
147 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
148 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
149 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
150 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
155 QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
157 switch (tableColumn) {
158 case CoreHighlightSettingsPage::EnableColumn:
159 return tr("Enable/disable this rule");
161 case CoreHighlightSettingsPage::NameColumn:
162 return tr("Phrase to match");
164 case CoreHighlightSettingsPage::RegExColumn:
165 return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
166 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
169 case CoreHighlightSettingsPage::CsColumn:
170 return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
171 "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
173 case CoreHighlightSettingsPage::SenderColumn:
174 return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
175 "leave blank to match any nickname.</p>"
176 "<p><i>Example:</i><br />"
177 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
178 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
179 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
180 "<p>If only inverted names are specified, it will match anything except for "
181 "what's specified (implicit wildcard).</p>"
182 "<p><i>Example:</i><br />"
183 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
184 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
185 "any nickname starting with <i>Announce</i></p>");
187 case CoreHighlightSettingsPage::ChanColumn:
188 return tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
189 "match any name.</p>"
190 "<p><i>Example:</i><br />"
191 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
192 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
193 "except for <i>#quasseldroid</i><br />"
194 "<p>If only inverted names are specified, it will match anything except for "
195 "what's specified (implicit wildcard).</p>"
196 "<p><i>Example:</i><br />"
197 "<i>!#quassel*; !#foobar</i><br />"
198 "would match anything except for <i>#foobar</i> or any channel starting with "
199 "<i>#quassel</i></p>");
202 // This shouldn't happen
203 return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
208 void CoreHighlightSettingsPage::setupTableTooltips(QWidget *enableWidget, QWidget *nameWidget,
209 QWidget *regExWidget, QWidget *csWidget,
210 QWidget *senderWidget, QWidget *chanWidget) const
212 // Make sure everything's valid
213 Q_ASSERT(enableWidget);
214 Q_ASSERT(nameWidget);
215 Q_ASSERT(regExWidget);
217 Q_ASSERT(senderWidget);
218 Q_ASSERT(chanWidget);
220 // Set tooltips and "What's this?" prompts
222 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
223 enableWidget->setWhatsThis(enableWidget->toolTip());
226 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
227 nameWidget->setWhatsThis(nameWidget->toolTip());
230 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
231 regExWidget->setWhatsThis(regExWidget->toolTip());
234 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
235 csWidget->setWhatsThis(csWidget->toolTip());
238 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
239 senderWidget->setWhatsThis(senderWidget->toolTip());
241 // Channel/buffer name
242 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
243 chanWidget->setWhatsThis(chanWidget->toolTip());
247 void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem *enableWidget,
248 QTableWidgetItem *nameWidget,
249 QTableWidgetItem *regExWidget,
250 QTableWidgetItem *csWidget,
251 QTableWidgetItem *senderWidget,
252 QTableWidgetItem *chanWidget) const
254 // Make sure everything's valid
255 Q_ASSERT(enableWidget);
256 Q_ASSERT(nameWidget);
257 Q_ASSERT(regExWidget);
259 Q_ASSERT(senderWidget);
260 Q_ASSERT(chanWidget);
262 // Set tooltips and "What's this?" prompts
264 enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
265 enableWidget->setWhatsThis(enableWidget->toolTip());
268 nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
269 nameWidget->setWhatsThis(nameWidget->toolTip());
272 regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
273 regExWidget->setWhatsThis(regExWidget->toolTip());
276 csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
277 csWidget->setWhatsThis(csWidget->toolTip());
280 senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
281 senderWidget->setWhatsThis(senderWidget->toolTip());
283 // Channel/buffer name
284 chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
285 chanWidget->setWhatsThis(chanWidget->toolTip());
289 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
291 // Assume connected state as enforced by the settings page UI
292 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
293 // Either disconnected or core supports highlights, enable highlight configuration and hide
294 // warning. Don't show the warning needlessly when disconnected.
295 ui.highlightsConfigWidget->setEnabled(true);
296 ui.coreUnsupportedWidget->setVisible(false);
298 // Core does not support highlights, show warning and disable highlight configuration
299 ui.highlightsConfigWidget->setEnabled(false);
300 ui.coreUnsupportedWidget->setVisible(true);
305 void CoreHighlightSettingsPage::clientConnected()
307 connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
311 void CoreHighlightSettingsPage::revert()
316 setChangedState(false);
321 bool CoreHighlightSettingsPage::hasDefaults() const
327 void CoreHighlightSettingsPage::defaults()
329 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
330 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
331 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
332 ui.nicksCaseSensitive->setChecked(false);
333 emptyHighlightTable();
340 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, int id, const QString &name, bool regex, bool cs,
341 const QString &sender, const QString &chanName, bool self)
343 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
349 auto *nameItem = new QTableWidgetItem(name);
351 auto *regexItem = new QTableWidgetItem("");
353 regexItem->setCheckState(Qt::Checked);
355 regexItem->setCheckState(Qt::Unchecked);
356 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
358 auto *csItem = new QTableWidgetItem("");
360 csItem->setCheckState(Qt::Checked);
362 csItem->setCheckState(Qt::Unchecked);
363 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
365 auto *enableItem = new QTableWidgetItem("");
367 enableItem->setCheckState(Qt::Checked);
369 enableItem->setCheckState(Qt::Unchecked);
370 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
372 auto *senderItem = new QTableWidgetItem(sender);
374 auto *chanNameItem = new QTableWidgetItem(chanName);
376 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
378 int lastRow = ui.highlightTable->rowCount() - 1;
379 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
380 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
381 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
382 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
383 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
384 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
387 ui.highlightTable->setCurrentItem(nameItem);
389 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
393 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, int id, const QString &name, bool regex, bool cs,
394 const QString &sender, const QString &chanName, bool self)
396 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
402 auto *nameItem = new QTableWidgetItem(name);
404 auto *regexItem = new QTableWidgetItem("");
406 regexItem->setCheckState(Qt::Checked);
408 regexItem->setCheckState(Qt::Unchecked);
409 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
411 auto *csItem = new QTableWidgetItem("");
413 csItem->setCheckState(Qt::Checked);
415 csItem->setCheckState(Qt::Unchecked);
416 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
418 auto *enableItem = new QTableWidgetItem("");
420 enableItem->setCheckState(Qt::Checked);
422 enableItem->setCheckState(Qt::Unchecked);
423 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
425 auto *chanNameItem = new QTableWidgetItem(chanName);
427 auto *senderItem = new QTableWidgetItem(sender);
429 setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
431 int lastRow = ui.ignoredTable->rowCount() - 1;
432 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
433 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
434 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
435 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
436 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
437 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
440 ui.ignoredTable->setCurrentItem(nameItem);
442 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
446 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
448 QList<int> selectedRows;
449 QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
450 for (auto selectedItem : selectedItemList) {
451 selectedRows.append(selectedItem->row());
453 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
455 for (auto row : selectedRows) {
456 if (row != lastRow) {
457 ui.highlightTable->removeRow(row);
458 highlightList.removeAt(row);
465 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
467 QList<int> selectedRows;
468 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
469 for (auto selectedItem : selectedItemList) {
470 selectedRows.append(selectedItem->row());
472 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
474 for (auto row : selectedRows) {
475 if (row != lastRow) {
476 ui.ignoredTable->removeRow(row);
477 ignoredList.removeAt(row);
484 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
486 // Only allow toggling "Case sensitive" when a nickname will be highlighted
487 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
488 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
492 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
494 int row = item->row();
495 bool selected = item->isSelected();
497 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
502 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
504 int row = item->row();
505 bool selected = item->isSelected();
507 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
512 void CoreHighlightSettingsPage::emptyHighlightTable()
514 // ui.highlight and highlightList should have the same size, but just to make sure.
515 if (ui.highlightTable->rowCount() != highlightList.size()) {
516 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
518 while (ui.highlightTable->rowCount()) {
519 ui.highlightTable->removeRow(0);
521 highlightList.clear();
525 void CoreHighlightSettingsPage::emptyIgnoredTable()
527 // ui.highlight and highlightList should have the same size, but just to make sure.
528 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
529 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
531 while (ui.ignoredTable->rowCount()) {
532 ui.ignoredTable->removeRow(0);
538 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
540 if (item->row() + 1 > highlightList.size())
543 auto highlightRule = highlightList.value(item->row());
546 switch (item->column()) {
547 case CoreHighlightSettingsPage::EnableColumn:
548 highlightRule.isEnabled = (item->checkState() == Qt::Checked);
550 case CoreHighlightSettingsPage::NameColumn:
551 if (item->text() == "")
552 item->setText(tr("this shouldn't be empty"));
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 if (item->text() == "")
591 item->setText(tr("this shouldn't be empty"));
592 ignoredRule.name = item->text();
594 case CoreHighlightSettingsPage::RegExColumn:
595 ignoredRule.isRegEx = (item->checkState() == Qt::Checked);
597 case CoreHighlightSettingsPage::CsColumn:
598 ignoredRule.isCaseSensitive = (item->checkState() == Qt::Checked);
600 case CoreHighlightSettingsPage::SenderColumn:
601 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
603 ignoredRule.sender = item->text();
605 case CoreHighlightSettingsPage::ChanColumn:
606 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
608 ignoredRule.chanName = item->text();
611 ignoredList[item->row()] = ignoredRule;
612 emit widgetHasChanged();
616 void CoreHighlightSettingsPage::load()
618 emptyHighlightTable();
621 auto ruleManager = Client::highlightRuleManager();
623 for (auto &rule : ruleManager->highlightRuleList()) {
624 if (rule.isInverse) {
625 addNewIgnoredRow(rule.isEnabled,
629 rule.isCaseSensitive,
634 addNewHighlightRow(rule.isEnabled, rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender,
639 int highlightNickType = ruleManager->highlightNick();
640 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
641 // Trigger the initial update of nicksCaseSensitive being enabled or not
642 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
643 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
645 setChangedState(false);
653 void CoreHighlightSettingsPage::save()
661 auto ruleManager = Client::highlightRuleManager();
662 if (ruleManager == nullptr)
665 auto clonedManager = HighlightRuleManager();
666 clonedManager.fromVariantMap(ruleManager->toVariantMap());
667 clonedManager.clear();
669 for (auto &rule : highlightList) {
670 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false,
671 rule.sender, rule.chanName);
674 for (auto &rule : ignoredList) {
675 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true,
676 rule.sender, rule.chanName);
679 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
681 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
682 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
684 ruleManager->requestUpdate(clonedManager.toVariantMap());
685 setChangedState(false);
690 int CoreHighlightSettingsPage::nextId()
693 for (int i = 0; i < highlightList.count(); i++) {
694 int id = highlightList[i].id;
699 for (int i = 0; i < ignoredList.count(); i++) {
700 int id = ignoredList[i].id;
709 void CoreHighlightSettingsPage::widgetHasChanged()
711 setChangedState(true);
715 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
717 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
718 // spaces to non-breaking
719 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
721 const QString remoteHighlightsMsgText =
722 QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>"
723 ).arg(tr("Your Quassel core is too old to support remote highlights"),
724 tr("You need a Quassel core v0.13.0 or newer to configure remote "
726 tr("You can still configure highlights for this device only in "
727 "<i>%1</i>.").arg(localHighlightsName));
729 QMessageBox::warning(this,
730 tr("Remote Highlights unsupported"),
731 remoteHighlightsMsgText);
735 void CoreHighlightSettingsPage::importRules()
737 NotificationSettings notificationSettings;
739 const auto localHighlightList = notificationSettings.highlightList();
741 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
742 // forcing all spaces to non-breaking
743 QString localHighlightsName;
744 if (Quassel::runMode() == Quassel::Monolithic) {
745 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
747 localHighlightsName = tr("Local Highlights").replace(" ", " ");
750 if (localHighlightList.count() == 0) {
751 // No highlight rules exist to import, do nothing
752 QMessageBox::information(this,
753 tr("No highlights to import"),
754 tr("No highlight rules in <i>%1</i>."
755 ).arg(localHighlightsName));
759 int ret = QMessageBox::question(this,
760 tr("Import highlights?"),
761 tr("Import all highlight rules from <i>%1</i>?"
762 ).arg(localHighlightsName),
763 QMessageBox::Yes|QMessageBox::No,
766 if (ret != QMessageBox::Yes) {
767 // Only two options, Yes or No, return if not Yes
772 // Save existing changes first to avoid overwriting them
776 auto clonedManager = HighlightRuleManager();
777 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
779 for (const auto &variant : notificationSettings.highlightList()) {
780 auto highlightRule = variant.toMap();
782 clonedManager.addHighlightRule(
783 clonedManager.nextId(),
784 highlightRule["Name"].toString(),
785 highlightRule["RegEx"].toBool(),
786 highlightRule["CS"].toBool(),
787 highlightRule["Enable"].toBool(),
790 highlightRule["Channel"].toString()
794 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
795 setChangedState(false);
798 // Give a heads-up that all succeeded
799 QMessageBox::information(this,
800 tr("Imported highlights"),
801 tr("%1 highlight rules successfully imported."
802 ).arg(QString::number(localHighlightList.count())));
806 bool CoreHighlightSettingsPage::isSelectable() const
808 return Client::isConnected();
809 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
810 // a friendly error message.