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 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setToolTip(
133 tr("Enable/disable this rule"));
134 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setWhatsThis(
135 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->toolTip());
137 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setToolTip(
138 tr("Phrase to match"));
139 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setWhatsThis(
140 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->toolTip());
142 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip(
143 tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
144 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
146 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis(
147 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->toolTip());
149 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip(
150 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>."));
152 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis(
153 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->toolTip());
155 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setToolTip(
156 tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
157 "leave blank to match any nickname.</p>"
158 "<p><i>Example:</i><br />"
159 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
160 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
161 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
162 "<p>If only inverted names are specified, it will match anything except for "
163 "what's specified (implicit wildcard).</p>"
164 "<p><i>Example:</i><br />"
165 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
166 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
167 "any nickname starting with <i>Announce</i></p>"));
168 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setWhatsThis(
169 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->toolTip());
171 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip(
172 tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
173 "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>"));
184 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis(
185 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->toolTip());
187 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
188 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
189 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
190 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
191 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
192 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
194 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
195 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
196 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
197 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
198 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
203 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
205 // Assume connected state as enforced by the settings page UI
206 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
207 // Either disconnected or core supports highlights, enable highlight configuration and hide
208 // warning. Don't show the warning needlessly when disconnected.
209 ui.highlightsConfigWidget->setEnabled(true);
210 ui.coreUnsupportedWidget->setVisible(false);
212 // Core does not support highlights, show warning and disable highlight configuration
213 ui.highlightsConfigWidget->setEnabled(false);
214 ui.coreUnsupportedWidget->setVisible(true);
219 void CoreHighlightSettingsPage::clientConnected()
221 connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
225 void CoreHighlightSettingsPage::revert()
230 setChangedState(false);
235 bool CoreHighlightSettingsPage::hasDefaults() const
241 void CoreHighlightSettingsPage::defaults()
243 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
244 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
245 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
246 ui.nicksCaseSensitive->setChecked(false);
247 emptyHighlightTable();
254 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, int id, const QString &name, bool regex, bool cs,
255 const QString &sender, const QString &chanName, bool self)
257 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
263 auto *nameItem = new QTableWidgetItem(name);
265 auto *regexItem = new QTableWidgetItem("");
267 regexItem->setCheckState(Qt::Checked);
269 regexItem->setCheckState(Qt::Unchecked);
270 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
272 auto *csItem = new QTableWidgetItem("");
274 csItem->setCheckState(Qt::Checked);
276 csItem->setCheckState(Qt::Unchecked);
277 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
279 auto *enableItem = new QTableWidgetItem("");
281 enableItem->setCheckState(Qt::Checked);
283 enableItem->setCheckState(Qt::Unchecked);
284 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
286 auto *senderItem = new QTableWidgetItem(sender);
288 auto *chanNameItem = new QTableWidgetItem(chanName);
290 enableItem->setToolTip(tr("Enable/disable this rule"));
291 nameItem->setToolTip(tr("Phrase to match"));
292 regexItem->setToolTip(
293 tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
294 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
297 tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
298 "<i>Channel</i> should be interpreted <b>case sensitive</b>."));
299 senderItem->setToolTip(
300 tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
301 "leave blank to match any nickname.</p>"
302 "<p><i>Example:</i><br />"
303 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
304 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
305 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
306 "<p>If only inverted names are specified, it will match anything except for "
307 "what's specified (implicit wildcard).</p>"
308 "<p><i>Example:</i><br />"
309 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
310 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
311 "any nickname starting with <i>Announce</i></p>"));
312 chanNameItem->setToolTip(
313 tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
314 "match any name.</p>"
315 "<p><i>Example:</i><br />"
316 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
317 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
318 "except for <i>#quasseldroid</i><br />"
319 "<p>If only inverted names are specified, it will match anything except for "
320 "what's specified (implicit wildcard).</p>"
321 "<p><i>Example:</i><br />"
322 "<i>!#quassel*; !#foobar</i><br />"
323 "would match anything except for <i>#foobar</i> or any channel starting with "
324 "<i>#quassel</i></p>"));
326 int lastRow = ui.highlightTable->rowCount() - 1;
327 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
328 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
329 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
330 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
331 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
332 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
335 ui.highlightTable->setCurrentItem(nameItem);
337 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
341 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, int id, const QString &name, bool regex, bool cs,
342 const QString &sender, const QString &chanName, bool self)
344 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
350 auto *nameItem = new QTableWidgetItem(name);
352 auto *regexItem = new QTableWidgetItem("");
354 regexItem->setCheckState(Qt::Checked);
356 regexItem->setCheckState(Qt::Unchecked);
357 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
359 auto *csItem = new QTableWidgetItem("");
361 csItem->setCheckState(Qt::Checked);
363 csItem->setCheckState(Qt::Unchecked);
364 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
366 auto *enableItem = new QTableWidgetItem("");
368 enableItem->setCheckState(Qt::Checked);
370 enableItem->setCheckState(Qt::Unchecked);
371 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
373 auto *chanNameItem = new QTableWidgetItem(chanName);
375 auto *senderItem = new QTableWidgetItem(sender);
377 enableItem->setToolTip(tr("Enable/disable this rule"));
378 nameItem->setToolTip(tr("Phrase to match"));
379 regexItem->setToolTip(
380 tr("<b>RegEx</b>: This option determines if the highlight rule should be "
381 "interpreted as a <b>regular expression</b> or just as a keyword."));
383 tr("<b>CS</b>: This option determines if the highlight rule should be interpreted "
384 "<b>case sensitive</b>."));
385 senderItem->setToolTip(
386 tr("<b>Sender</b>: This option specifies which sender nicknames match. Leave "
387 "blank to match any nickname."));
388 chanNameItem->setToolTip(
389 tr("<p><b>Channel</b>: Semicolon separated list of channel names.</p>"
390 "<p><i>Example:</i><br />"
391 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
392 "would match on #foobar and any channel starting with <i>#quassel</i> except "
393 "for <i>#quasseldroid</i><br />"
394 "<p>If only inverted names are specified, it will match anything except for "
395 "what's specified (implicit wildcard).</p>"
396 "<p><i>Example:</i><br />"
397 "<i>!#quassel*; !#foobar</i><br />"
398 "would match anything except for #foobar or any channel starting with "
399 "<i>#quassel</i></p>"));
401 int lastRow = ui.ignoredTable->rowCount() - 1;
402 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
403 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
404 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
405 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
406 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
407 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
410 ui.ignoredTable->setCurrentItem(nameItem);
412 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 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
425 for (auto row : selectedRows) {
426 if (row != lastRow) {
427 ui.highlightTable->removeRow(row);
428 highlightList.removeAt(row);
435 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
437 QList<int> selectedRows;
438 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
439 for (auto selectedItem : selectedItemList) {
440 selectedRows.append(selectedItem->row());
442 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
444 for (auto row : selectedRows) {
445 if (row != lastRow) {
446 ui.ignoredTable->removeRow(row);
447 ignoredList.removeAt(row);
454 void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
456 // Only allow toggling "Case sensitive" when a nickname will be highlighted
457 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
458 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
462 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
464 int row = item->row();
465 bool selected = item->isSelected();
467 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
472 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
474 int row = item->row();
475 bool selected = item->isSelected();
477 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
482 void CoreHighlightSettingsPage::emptyHighlightTable()
484 // ui.highlight and highlightList should have the same size, but just to make sure.
485 if (ui.highlightTable->rowCount() != highlightList.size()) {
486 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
488 while (ui.highlightTable->rowCount()) {
489 ui.highlightTable->removeRow(0);
491 highlightList.clear();
495 void CoreHighlightSettingsPage::emptyIgnoredTable()
497 // ui.highlight and highlightList should have the same size, but just to make sure.
498 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
499 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
501 while (ui.ignoredTable->rowCount()) {
502 ui.ignoredTable->removeRow(0);
508 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
510 if (item->row() + 1 > highlightList.size())
513 auto highlightRule = highlightList.value(item->row());
516 switch (item->column()) {
517 case CoreHighlightSettingsPage::EnableColumn:
518 highlightRule.isEnabled = (item->checkState() == Qt::Checked);
520 case CoreHighlightSettingsPage::NameColumn:
521 if (item->text() == "")
522 item->setText(tr("this shouldn't be empty"));
523 highlightRule.name = item->text();
525 case CoreHighlightSettingsPage::RegExColumn:
526 highlightRule.isRegEx = (item->checkState() == Qt::Checked);
528 case CoreHighlightSettingsPage::CsColumn:
529 highlightRule.isCaseSensitive = (item->checkState() == Qt::Checked);
531 case CoreHighlightSettingsPage::SenderColumn:
532 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
534 highlightRule.sender = item->text();
536 case CoreHighlightSettingsPage::ChanColumn:
537 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
539 highlightRule.chanName = item->text();
542 highlightList[item->row()] = highlightRule;
543 emit widgetHasChanged();
547 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
549 if (item->row() + 1 > ignoredList.size())
552 auto ignoredRule = ignoredList.value(item->row());
555 switch (item->column()) {
556 case CoreHighlightSettingsPage::EnableColumn:
557 ignoredRule.isEnabled = (item->checkState() == Qt::Checked);
559 case CoreHighlightSettingsPage::NameColumn:
560 if (item->text() == "")
561 item->setText(tr("this shouldn't be empty"));
562 ignoredRule.name = item->text();
564 case CoreHighlightSettingsPage::RegExColumn:
565 ignoredRule.isRegEx = (item->checkState() == Qt::Checked);
567 case CoreHighlightSettingsPage::CsColumn:
568 ignoredRule.isCaseSensitive = (item->checkState() == Qt::Checked);
570 case CoreHighlightSettingsPage::SenderColumn:
571 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
573 ignoredRule.sender = item->text();
575 case CoreHighlightSettingsPage::ChanColumn:
576 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
578 ignoredRule.chanName = item->text();
581 ignoredList[item->row()] = ignoredRule;
582 emit widgetHasChanged();
586 void CoreHighlightSettingsPage::load()
588 emptyHighlightTable();
591 auto ruleManager = Client::highlightRuleManager();
593 for (auto &rule : ruleManager->highlightRuleList()) {
594 if (rule.isInverse) {
595 addNewIgnoredRow(rule.isEnabled,
599 rule.isCaseSensitive,
604 addNewHighlightRow(rule.isEnabled, rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender,
609 int highlightNickType = ruleManager->highlightNick();
610 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
611 // Trigger the initial update of nicksCaseSensitive being enabled or not
612 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
613 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
615 setChangedState(false);
623 void CoreHighlightSettingsPage::save()
631 auto ruleManager = Client::highlightRuleManager();
632 if (ruleManager == nullptr)
635 auto clonedManager = HighlightRuleManager();
636 clonedManager.fromVariantMap(ruleManager->toVariantMap());
637 clonedManager.clear();
639 for (auto &rule : highlightList) {
640 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false,
641 rule.sender, rule.chanName);
644 for (auto &rule : ignoredList) {
645 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true,
646 rule.sender, rule.chanName);
649 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
651 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
652 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
654 ruleManager->requestUpdate(clonedManager.toVariantMap());
655 setChangedState(false);
660 int CoreHighlightSettingsPage::nextId()
663 for (int i = 0; i < highlightList.count(); i++) {
664 int id = highlightList[i].id;
669 for (int i = 0; i < ignoredList.count(); i++) {
670 int id = ignoredList[i].id;
679 void CoreHighlightSettingsPage::widgetHasChanged()
681 setChangedState(true);
685 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
687 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
688 // spaces to non-breaking
689 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
691 const QString remoteHighlightsMsgText =
692 QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>"
693 ).arg(tr("Your Quassel core is too old to support remote highlights"),
694 tr("You need a Quassel core v0.13.0 or newer to configure remote "
696 tr("You can still configure highlights for this device only in "
697 "<i>%1</i>.").arg(localHighlightsName));
699 QMessageBox::warning(this,
700 tr("Remote Highlights unsupported"),
701 remoteHighlightsMsgText);
705 void CoreHighlightSettingsPage::importRules()
707 NotificationSettings notificationSettings;
709 const auto localHighlightList = notificationSettings.highlightList();
711 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
712 // forcing all spaces to non-breaking
713 QString localHighlightsName;
714 if (Quassel::runMode() == Quassel::Monolithic) {
715 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
717 localHighlightsName = tr("Local Highlights").replace(" ", " ");
720 if (localHighlightList.count() == 0) {
721 // No highlight rules exist to import, do nothing
722 QMessageBox::information(this,
723 tr("No highlights to import"),
724 tr("No highlight rules in <i>%1</i>."
725 ).arg(localHighlightsName));
729 int ret = QMessageBox::question(this,
730 tr("Import highlights?"),
731 tr("Import all highlight rules from <i>%1</i>?"
732 ).arg(localHighlightsName),
733 QMessageBox::Yes|QMessageBox::No,
736 if (ret != QMessageBox::Yes) {
737 // Only two options, Yes or No, return if not Yes
742 // Save existing changes first to avoid overwriting them
746 auto clonedManager = HighlightRuleManager();
747 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
749 for (const auto &variant : notificationSettings.highlightList()) {
750 auto highlightRule = variant.toMap();
752 clonedManager.addHighlightRule(
753 clonedManager.nextId(),
754 highlightRule["Name"].toString(),
755 highlightRule["RegEx"].toBool(),
756 highlightRule["CS"].toBool(),
757 highlightRule["Enable"].toBool(),
760 highlightRule["Channel"].toString()
764 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
765 setChangedState(false);
768 // Give a heads-up that all succeeded
769 QMessageBox::information(this,
770 tr("Imported highlights"),
771 tr("%1 highlight rules successfully imported."
772 ).arg(QString::number(localHighlightList.count())));
776 bool CoreHighlightSettingsPage::isSelectable() const
778 return Client::isConnected();
779 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
780 // a friendly error message.