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
114 void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state)
116 updateCoreSupportStatus(state);
125 void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const
127 table->verticalHeader()->hide();
128 table->setShowGrid(false);
130 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setToolTip(
131 tr("Enable/disable this rule"));
132 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setWhatsThis(
133 table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->toolTip());
135 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setToolTip(
136 tr("Phrase to match"));
137 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setWhatsThis(
138 table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->toolTip());
140 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip(
141 tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
142 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
144 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis(
145 table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->toolTip());
147 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip(
148 tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
149 "<i>Channel</i> should be interpreted <b>case sensitive</b>."));
150 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis(
151 table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->toolTip());
153 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setToolTip(
154 tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
155 "leave blank to match any nickname.</p>"
156 "<p><i>Example:</i><br />"
157 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
158 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
159 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
160 "<p>If only inverted names are specified, it will match anything except for "
161 "what's specified (implicit wildcard).</p>"
162 "<p><i>Example:</i><br />"
163 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
164 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
165 "any nickname starting with <i>Announce</i></p>"));
166 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setWhatsThis(
167 table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->toolTip());
169 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip(
170 tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
171 "match any name.</p>"
172 "<p><i>Example:</i><br />"
173 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
174 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
175 "except for <i>#quasseldroid</i><br />"
176 "<p>If only inverted names are specified, it will match anything except for "
177 "what's specified (implicit wildcard).</p>"
178 "<p><i>Example:</i><br />"
179 "<i>!#quassel*; !#foobar</i><br />"
180 "would match anything except for <i>#foobar</i> or any channel starting with "
181 "<i>#quassel</i></p>"));
182 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis(
183 table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->toolTip());
185 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
186 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
187 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
188 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
189 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
190 table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
192 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
193 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
194 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
195 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
196 table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
200 void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
202 // Assume connected state as enforced by the settings page UI
203 if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) {
204 // Either disconnected or core supports highlights, enable highlight configuration and hide
205 // warning. Don't show the warning needlessly when disconnected.
206 ui.highlightsConfigWidget->setEnabled(true);
207 ui.coreUnsupportedWidget->setVisible(false);
209 // Core does not support highlights, show warning and disable highlight configuration
210 ui.highlightsConfigWidget->setEnabled(false);
211 ui.coreUnsupportedWidget->setVisible(true);
215 void CoreHighlightSettingsPage::clientConnected()
217 connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
220 void CoreHighlightSettingsPage::revert()
225 setChangedState(false);
229 bool CoreHighlightSettingsPage::hasDefaults() const
234 void CoreHighlightSettingsPage::defaults()
236 int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
237 int defaultIndex = ui.highlightNicksComboBox->findData(QVariant(highlightNickType));
238 ui.highlightNicksComboBox->setCurrentIndex(defaultIndex);
239 ui.nicksCaseSensitive->setChecked(false);
240 emptyHighlightTable();
246 void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, int id, const QString &name, bool regex, bool cs,
247 const QString &sender, const QString &chanName, bool self)
249 ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1);
255 auto *nameItem = new QTableWidgetItem(name);
257 auto *regexItem = new QTableWidgetItem("");
259 regexItem->setCheckState(Qt::Checked);
261 regexItem->setCheckState(Qt::Unchecked);
262 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
264 auto *csItem = new QTableWidgetItem("");
266 csItem->setCheckState(Qt::Checked);
268 csItem->setCheckState(Qt::Unchecked);
269 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
271 auto *enableItem = new QTableWidgetItem("");
273 enableItem->setCheckState(Qt::Checked);
275 enableItem->setCheckState(Qt::Unchecked);
276 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
278 auto *senderItem = new QTableWidgetItem(sender);
280 auto *chanNameItem = new QTableWidgetItem(chanName);
282 enableItem->setToolTip(tr("Enable/disable this rule"));
283 nameItem->setToolTip(tr("Phrase to match"));
284 regexItem->setToolTip(
285 tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
286 "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
289 tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
290 "<i>Channel</i> should be interpreted <b>case sensitive</b>."));
291 senderItem->setToolTip(
292 tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
293 "leave blank to match any nickname.</p>"
294 "<p><i>Example:</i><br />"
295 "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
296 "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
297 "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
298 "<p>If only inverted names are specified, it will match anything except for "
299 "what's specified (implicit wildcard).</p>"
300 "<p><i>Example:</i><br />"
301 "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
302 "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
303 "any nickname starting with <i>Announce</i></p>"));
304 chanNameItem->setToolTip(
305 tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
306 "match any name.</p>"
307 "<p><i>Example:</i><br />"
308 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
309 "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
310 "except for <i>#quasseldroid</i><br />"
311 "<p>If only inverted names are specified, it will match anything except for "
312 "what's specified (implicit wildcard).</p>"
313 "<p><i>Example:</i><br />"
314 "<i>!#quassel*; !#foobar</i><br />"
315 "would match anything except for <i>#foobar</i> or any channel starting with "
316 "<i>#quassel</i></p>"));
318 int lastRow = ui.highlightTable->rowCount() - 1;
319 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
320 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
321 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
322 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
323 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
324 ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
327 ui.highlightTable->setCurrentItem(nameItem);
329 highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName);
332 void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, int id, const QString &name, bool regex, bool cs,
333 const QString &sender, const QString &chanName, bool self)
335 ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1);
341 auto *nameItem = new QTableWidgetItem(name);
343 auto *regexItem = new QTableWidgetItem("");
345 regexItem->setCheckState(Qt::Checked);
347 regexItem->setCheckState(Qt::Unchecked);
348 regexItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
350 auto *csItem = new QTableWidgetItem("");
352 csItem->setCheckState(Qt::Checked);
354 csItem->setCheckState(Qt::Unchecked);
355 csItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
357 auto *enableItem = new QTableWidgetItem("");
359 enableItem->setCheckState(Qt::Checked);
361 enableItem->setCheckState(Qt::Unchecked);
362 enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
364 auto *chanNameItem = new QTableWidgetItem(chanName);
366 auto *senderItem = new QTableWidgetItem(sender);
368 enableItem->setToolTip(tr("Enable/disable this rule"));
369 nameItem->setToolTip(tr("Phrase to match"));
370 regexItem->setToolTip(
371 tr("<b>RegEx</b>: This option determines if the highlight rule should be "
372 "interpreted as a <b>regular expression</b> or just as a keyword."));
374 tr("<b>CS</b>: This option determines if the highlight rule should be interpreted "
375 "<b>case sensitive</b>."));
376 senderItem->setToolTip(
377 tr("<b>Sender</b>: This option specifies which sender nicknames match. Leave "
378 "blank to match any nickname."));
379 chanNameItem->setToolTip(
380 tr("<p><b>Channel</b>: Semicolon separated list of channel names.</p>"
381 "<p><i>Example:</i><br />"
382 "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
383 "would match on #foobar and any channel starting with <i>#quassel</i> except "
384 "for <i>#quasseldroid</i><br />"
385 "<p>If only inverted names are specified, it will match anything except for "
386 "what's specified (implicit wildcard).</p>"
387 "<p><i>Example:</i><br />"
388 "<i>!#quassel*; !#foobar</i><br />"
389 "would match anything except for #foobar or any channel starting with "
390 "<i>#quassel</i></p>"));
392 int lastRow = ui.ignoredTable->rowCount() - 1;
393 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
394 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
395 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
396 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
397 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
398 ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
401 ui.ignoredTable->setCurrentItem(nameItem);
403 ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName);
406 void CoreHighlightSettingsPage::removeSelectedHighlightRows()
408 QList<int> selectedRows;
409 QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
410 for (auto selectedItem : selectedItemList) {
411 selectedRows.append(selectedItem->row());
413 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
415 for (auto row : selectedRows) {
416 if (row != lastRow) {
417 ui.highlightTable->removeRow(row);
418 highlightList.removeAt(row);
424 void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
426 QList<int> selectedRows;
427 QList<QTableWidgetItem *> selectedItemList = ui.ignoredTable->selectedItems();
428 for (auto selectedItem : selectedItemList) {
429 selectedRows.append(selectedItem->row());
431 qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
433 for (auto row : selectedRows) {
434 if (row != lastRow) {
435 ui.ignoredTable->removeRow(row);
436 ignoredList.removeAt(row);
442 void CoreHighlightSettingsPage::highlightNicksChanged(const int index) {
443 // Only allow toggling "Case sensitive" when a nickname will be highlighted
444 auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
445 ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
448 void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
450 int row = item->row();
451 bool selected = item->isSelected();
453 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
457 void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
459 int row = item->row();
460 bool selected = item->isSelected();
462 ->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount - 1),
466 void CoreHighlightSettingsPage::emptyHighlightTable()
468 // ui.highlight and highlightList should have the same size, but just to make sure.
469 if (ui.highlightTable->rowCount() != highlightList.size()) {
470 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
472 while (ui.highlightTable->rowCount()) {
473 ui.highlightTable->removeRow(0);
475 highlightList.clear();
478 void CoreHighlightSettingsPage::emptyIgnoredTable()
480 // ui.highlight and highlightList should have the same size, but just to make sure.
481 if (ui.ignoredTable->rowCount() != ignoredList.size()) {
482 qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
484 while (ui.ignoredTable->rowCount()) {
485 ui.ignoredTable->removeRow(0);
490 void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
492 if (item->row() + 1 > highlightList.size())
495 auto highlightRule = highlightList.value(item->row());
498 switch (item->column()) {
499 case CoreHighlightSettingsPage::EnableColumn:
500 highlightRule.isEnabled = (item->checkState() == Qt::Checked);
502 case CoreHighlightSettingsPage::NameColumn:
503 if (item->text() == "")
504 item->setText(tr("this shouldn't be empty"));
505 highlightRule.name = item->text();
507 case CoreHighlightSettingsPage::RegExColumn:
508 highlightRule.isRegEx = (item->checkState() == Qt::Checked);
510 case CoreHighlightSettingsPage::CsColumn:
511 highlightRule.isCaseSensitive = (item->checkState() == Qt::Checked);
513 case CoreHighlightSettingsPage::SenderColumn:
514 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
516 highlightRule.sender = item->text();
518 case CoreHighlightSettingsPage::ChanColumn:
519 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
521 highlightRule.chanName = item->text();
524 highlightList[item->row()] = highlightRule;
525 emit widgetHasChanged();
528 void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
530 if (item->row() + 1 > ignoredList.size())
533 auto ignoredRule = ignoredList.value(item->row());
536 switch (item->column()) {
537 case CoreHighlightSettingsPage::EnableColumn:
538 ignoredRule.isEnabled = (item->checkState() == Qt::Checked);
540 case CoreHighlightSettingsPage::NameColumn:
541 if (item->text() == "")
542 item->setText(tr("this shouldn't be empty"));
543 ignoredRule.name = item->text();
545 case CoreHighlightSettingsPage::RegExColumn:
546 ignoredRule.isRegEx = (item->checkState() == Qt::Checked);
548 case CoreHighlightSettingsPage::CsColumn:
549 ignoredRule.isCaseSensitive = (item->checkState() == Qt::Checked);
551 case CoreHighlightSettingsPage::SenderColumn:
552 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
554 ignoredRule.sender = item->text();
556 case CoreHighlightSettingsPage::ChanColumn:
557 if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
559 ignoredRule.chanName = item->text();
562 ignoredList[item->row()] = ignoredRule;
563 emit widgetHasChanged();
566 void CoreHighlightSettingsPage::load()
568 emptyHighlightTable();
571 auto ruleManager = Client::highlightRuleManager();
573 for (auto &rule : ruleManager->highlightRuleList()) {
574 if (rule.isInverse) {
575 addNewIgnoredRow(rule.isEnabled,
579 rule.isCaseSensitive,
584 addNewHighlightRow(rule.isEnabled, rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender,
589 int highlightNickType = ruleManager->highlightNick();
590 ui.highlightNicksComboBox->setCurrentIndex(ui.highlightNicksComboBox->findData(QVariant(highlightNickType)));
591 // Trigger the initial update of nicksCaseSensitive being enabled or not
592 highlightNicksChanged(ui.highlightNicksComboBox->currentIndex());
593 ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
595 setChangedState(false);
602 void CoreHighlightSettingsPage::save()
610 auto ruleManager = Client::highlightRuleManager();
611 if (ruleManager == nullptr)
614 auto clonedManager = HighlightRuleManager();
615 clonedManager.fromVariantMap(ruleManager->toVariantMap());
616 clonedManager.clear();
618 for (auto &rule : highlightList) {
619 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false,
620 rule.sender, rule.chanName);
623 for (auto &rule : ignoredList) {
624 clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true,
625 rule.sender, rule.chanName);
628 auto highlightNickType = ui.highlightNicksComboBox->itemData(ui.highlightNicksComboBox->currentIndex()).value<int>();
630 clonedManager.setHighlightNick(HighlightRuleManager::HighlightNickType(highlightNickType));
631 clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
633 ruleManager->requestUpdate(clonedManager.toVariantMap());
634 setChangedState(false);
638 int CoreHighlightSettingsPage::nextId() {
640 for (int i = 0; i < highlightList.count(); i++) {
641 int id = highlightList[i].id;
646 for (int i = 0; i < ignoredList.count(); i++) {
647 int id = ignoredList[i].id;
655 void CoreHighlightSettingsPage::widgetHasChanged()
657 setChangedState(true);
660 void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked()
662 // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all
663 // spaces to non-breaking
664 const QString localHighlightsName = tr("Local Highlights").replace(" ", " ");
666 const QString remoteHighlightsMsgText =
667 QString("<p><b>%1</b></p></br><p>%2</p></br><p>%3</p>"
668 ).arg(tr("Your Quassel core is too old to support remote highlights"),
669 tr("You need a Quassel core v0.13.0 or newer to configure remote "
671 tr("You can still configure highlights for this device only in "
672 "<i>%1</i>.").arg(localHighlightsName));
674 QMessageBox::warning(this,
675 tr("Remote Highlights unsupported"),
676 remoteHighlightsMsgText);
679 void CoreHighlightSettingsPage::importRules() {
680 NotificationSettings notificationSettings;
682 const auto localHighlightList = notificationSettings.highlightList();
684 // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference,
685 // forcing all spaces to non-breaking
686 QString localHighlightsName;
687 if (Quassel::runMode() == Quassel::Monolithic) {
688 localHighlightsName = tr("Legacy Highlights").replace(" ", " ");
690 localHighlightsName = tr("Local Highlights").replace(" ", " ");
693 if (localHighlightList.count() == 0) {
694 // No highlight rules exist to import, do nothing
695 QMessageBox::information(this,
696 tr("No highlights to import"),
697 tr("No highlight rules in <i>%1</i>."
698 ).arg(localHighlightsName));
702 int ret = QMessageBox::question(this,
703 tr("Import highlights?"),
704 tr("Import all highlight rules from <i>%1</i>?"
705 ).arg(localHighlightsName),
706 QMessageBox::Yes|QMessageBox::No,
709 if (ret != QMessageBox::Yes) {
710 // Only two options, Yes or No, return if not Yes
714 auto clonedManager = HighlightRuleManager();
715 clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
717 for (const auto &variant : notificationSettings.highlightList()) {
718 auto highlightRule = variant.toMap();
720 clonedManager.addHighlightRule(
721 clonedManager.nextId(),
722 highlightRule["Name"].toString(),
723 highlightRule["RegEx"].toBool(),
724 highlightRule["CS"].toBool(),
725 highlightRule["Enable"].toBool(),
728 highlightRule["Channel"].toString()
732 Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap());
733 setChangedState(false);
736 // Give a heads-up that all succeeded
737 QMessageBox::information(this,
738 tr("Imported highlights"),
739 tr("%1 highlight rules successfully imported."
740 ).arg(QString::number(localHighlightList.count())));
743 bool CoreHighlightSettingsPage::isSelectable() const {
744 return Client::isConnected();
745 // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
746 // a friendly error message.