X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fsettingspages%2Fcorehighlightsettingspage.cpp;h=7e50229661df4edcd18926a196ef3f351e5229d4;hp=55266d0560af7a7960614670428567529794a0d3;hb=17c39210b1bce04795046657642de66292518fe6;hpb=0eb413175783a04999ce04c5db8a9b9132ea0d8c diff --git a/src/qtui/settingspages/corehighlightsettingspage.cpp b/src/qtui/settingspages/corehighlightsettingspage.cpp index 55266d05..7e502296 100644 --- a/src/qtui/settingspages/corehighlightsettingspage.cpp +++ b/src/qtui/settingspages/corehighlightsettingspage.cpp @@ -19,14 +19,20 @@ ***************************************************************************/ #include +#include #include #include "client.h" #include "corehighlightsettingspage.h" +#include "icon.h" #include "qtui.h" CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent) - : SettingsPage(tr("Interface"), tr("Remote Highlights"), parent) + : SettingsPage(tr("Interface"), + // In Monolithic mode, local highlights are replaced by remote highlights + Quassel::runMode() == Quassel::Monolithic ? + tr("Highlights") : tr("Remote Highlights"), + parent) { ui.setupUi(this); @@ -83,10 +89,31 @@ CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent) SLOT(ignoredTableChanged(QTableWidgetItem * ))); connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected())); + + // Warning icon + ui.coreUnsupportedIcon->setPixmap(icon::get("dialog-warning").pixmap(16)); + + // Set up client/monolithic remote highlights information + if (Quassel::runMode() == Quassel::Monolithic) { + // We're running in Monolithic mode, local highlights are considered legacy + ui.highlightImport->setText(tr("Import Legacy")); + ui.highlightImport->setToolTip(tr("Import highlight rules configured in %1.") + .arg(tr("Legacy Highlights").replace(" ", " "))); + // Re-use translations of "Legacy Highlights" as this is a word-for-word reference, forcing + // all spaces to be non-breaking + } else { + // We're running in client/split mode, local highlights are distinguished from remote + ui.highlightImport->setText(tr("Import Local")); + ui.highlightImport->setToolTip(tr("Import highlight rules configured in %1.") + .arg(tr("Local Highlights").replace(" ", " "))); + // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing + // all spaces to be non-breaking + } } void CoreHighlightSettingsPage::coreConnectionStateChanged(bool state) { + updateCoreSupportStatus(state); setEnabled(state); if (state) { load(); @@ -100,29 +127,57 @@ void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const table->verticalHeader()->hide(); table->setShowGrid(false); + table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setToolTip( + tr("Enable/disable this rule")); + table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->setWhatsThis( + table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn)->toolTip()); + + table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setToolTip( + tr("Phrase to match")); + table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->setWhatsThis( + table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn)->toolTip()); + table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip( - tr("RegEx: This option determines if the highlight rule should be " - "interpreted as a regular expression or just as a keyword.")); + tr("RegEx: This option determines if the highlight rule, Sender, and " + "Channel should be interpreted as regular expressions or just as " + "keywords.")); table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis( table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->toolTip()); table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip( - tr("CS: This option determines if the highlight rule should be interpreted " - "case sensitive.")); + tr("CS: This option determines if the highlight rule, Sender, and " + "Channel should be interpreted case sensitive.")); table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis( table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->toolTip()); + table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setToolTip( + tr("

Sender: Semicolon separated list of nick!ident@host names, " + "leave blank to match any nickname.

" + "

Example:
" + "Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*
" + "would match on Alice, Bob with hostmask example.com, and " + "any nickname starting with Carol except for Caroline
" + "

If only inverted names are specified, it will match anything except for " + "what's specified (implicit wildcard).

" + "

Example:
" + "!Announce*!*; !Wheatley!aperture@*
" + "would match anything except for Wheatley with ident aperture or " + "any nickname starting with Announce

")); + table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->setWhatsThis( + table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn)->toolTip()); + table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip( - tr("

Channel: Semicolon separated list of channel names.

" + tr("

Channel: Semicolon separated list of channel names, leave blank to " + "match any name.

" "

Example:
" "#quassel*; #foobar; !#quasseldroid
" - "would match on #foobar and on any channel starting with #quassel except " - "for #quasseldroid
" + "would match on #foobar and any channel starting with #quassel " + "except for #quasseldroid
" "

If only inverted names are specified, it will match anything except for " "what's specified (implicit wildcard).

" "

Example:
" "!#quassel*; !#foobar
" - "would match anything except for #foobar or any channel starting with " + "would match anything except for #foobar or any channel starting with " "#quassel

")); table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis( table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->toolTip()); @@ -142,6 +197,21 @@ void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const #endif } +void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state) +{ + // Assume connected state as enforced by the settings page UI + if (!state || Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights)) { + // Either disconnected or core supports highlights, enable highlight configuration and hide + // warning. Don't show the warning needlessly when disconnected. + ui.highlightsConfigWidget->setEnabled(true); + ui.coreUnsupportedWidget->setVisible(false); + } else { + // Core does not support highlights, show warning and disable highlight configuration + ui.highlightsConfigWidget->setEnabled(false); + ui.coreUnsupportedWidget->setVisible(true); + } +} + void CoreHighlightSettingsPage::clientConnected() { connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert())); @@ -173,11 +243,15 @@ void CoreHighlightSettingsPage::defaults() widgetHasChanged(); } -void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, const QString &name, bool regex, bool cs, +void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, int id, const QString &name, bool regex, bool cs, const QString &sender, const QString &chanName, bool self) { ui.highlightTable->setRowCount(ui.highlightTable->rowCount() + 1); + if (id < 0) { + id = nextId(); + } + auto *nameItem = new QTableWidgetItem(name); auto *regexItem = new QTableWidgetItem(""); @@ -201,32 +275,44 @@ void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, const QString &n enableItem->setCheckState(Qt::Unchecked); enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); - auto *chanNameItem = new QTableWidgetItem(chanName); - auto *senderItem = new QTableWidgetItem(sender); + auto *chanNameItem = new QTableWidgetItem(chanName); + enableItem->setToolTip(tr("Enable/disable this rule")); nameItem->setToolTip(tr("Phrase to match")); regexItem->setToolTip( - tr("RegEx: This option determines if the highlight rule should be " - "interpreted as a regular expression or just as a keyword.")); + tr("RegEx: This option determines if the highlight rule, Sender, and " + "Channel should be interpreted as regular expressions or just as " + "keywords.")); csItem->setToolTip( - tr("CS: This option determines if the highlight rule should be interpreted " - "case sensitive.")); + tr("CS: This option determines if the highlight rule, Sender, and " + "Channel should be interpreted case sensitive.")); senderItem->setToolTip( - tr("Sender: This option specifies which sender to match. Leave blank to " - "match any nickname.")); + tr("

Sender: Semicolon separated list of nick!ident@host names, " + "leave blank to match any nickname.

" + "

Example:
" + "Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*
" + "would match on Alice, Bob with hostmask example.com, and " + "any nickname starting with Carol except for Caroline
" + "

If only inverted names are specified, it will match anything except for " + "what's specified (implicit wildcard).

" + "

Example:
" + "!Announce*!*; !Wheatley!aperture@*
" + "would match anything except for Wheatley with ident aperture or " + "any nickname starting with Announce

")); chanNameItem->setToolTip( - tr("

Channel: Semicolon separated list of channel names.

" + tr("

Channel: Semicolon separated list of channel names, leave blank to " + "match any name.

" "

Example:
" "#quassel*; #foobar; !#quasseldroid
" - "would match on #foobar and on any channel starting with #quassel except " - "for #quasseldroid
" + "would match on #foobar and any channel starting with #quassel " + "except for #quasseldroid
" "

If only inverted names are specified, it will match anything except for " "what's specified (implicit wildcard).

" "

Example:
" "!#quassel*; !#foobar
" - "would match anything except for #foobar or any channel starting with " + "would match anything except for #foobar or any channel starting with " "#quassel

")); int lastRow = ui.highlightTable->rowCount() - 1; @@ -240,14 +326,18 @@ void CoreHighlightSettingsPage::addNewHighlightRow(bool enable, const QString &n if (!self) ui.highlightTable->setCurrentItem(nameItem); - highlightList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, false, sender, chanName); + highlightList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, false, sender, chanName); } -void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, const QString &name, bool regex, bool cs, +void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, int id, const QString &name, bool regex, bool cs, const QString &sender, const QString &chanName, bool self) { ui.ignoredTable->setRowCount(ui.ignoredTable->rowCount() + 1); + if (id < 0) { + id = nextId(); + } + auto *nameItem = new QTableWidgetItem(name); auto *regexItem = new QTableWidgetItem(""); @@ -290,7 +380,7 @@ void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, const QString &nam tr("

Channel: Semicolon separated list of channel names.

" "

Example:
" "#quassel*; #foobar; !#quasseldroid
" - "would match on #foobar and on any channel starting with #quassel except " + "would match on #foobar and any channel starting with #quassel except " "for #quasseldroid
" "

If only inverted names are specified, it will match anything except for " "what's specified (implicit wildcard).

" @@ -310,7 +400,7 @@ void CoreHighlightSettingsPage::addNewIgnoredRow(bool enable, const QString &nam if (!self) ui.ignoredTable->setCurrentItem(nameItem); - ignoredList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, true, sender, chanName); + ignoredList << HighlightRuleManager::HighlightRule(id, name, regex, cs, enable, true, sender, chanName); } void CoreHighlightSettingsPage::removeSelectedHighlightRows() @@ -483,6 +573,7 @@ void CoreHighlightSettingsPage::load() for (auto &rule : ruleManager->highlightRuleList()) { if (rule.isInverse) { addNewIgnoredRow(rule.isEnabled, + rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, @@ -490,7 +581,7 @@ void CoreHighlightSettingsPage::load() rule.chanName); } else { - addNewHighlightRow(rule.isEnabled, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender, + addNewHighlightRow(rule.isEnabled, rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.sender, rule.chanName); } } @@ -525,12 +616,12 @@ void CoreHighlightSettingsPage::save() clonedManager.clear(); for (auto &rule : highlightList) { - clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false, + clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, false, rule.sender, rule.chanName); } for (auto &rule : ignoredList) { - clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true, + clonedManager.addHighlightRule(rule.id, rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, true, rule.sender, rule.chanName); } @@ -544,14 +635,82 @@ void CoreHighlightSettingsPage::save() load(); } +int CoreHighlightSettingsPage::nextId() { + int max = 0; + for (int i = 0; i < highlightList.count(); i++) { + int id = highlightList[i].id; + if (id > max) { + max = id; + } + } + for (int i = 0; i < ignoredList.count(); i++) { + int id = ignoredList[i].id; + if (id > max) { + max = id; + } + } + return max+1; +} + void CoreHighlightSettingsPage::widgetHasChanged() { setChangedState(true); } +void CoreHighlightSettingsPage::on_coreUnsupportedDetails_clicked() +{ + // Re-use translations of "Local Highlights" as this is a word-for-word reference, forcing all + // spaces to non-breaking + const QString localHighlightsName = tr("Local Highlights").replace(" ", " "); + + const QString remoteHighlightsMsgText = + QString("

%1


%2


%3

" + ).arg(tr("Your Quassel core is too old to support remote highlights"), + tr("You need a Quassel core v0.13.0 or newer to configure remote " + "highlights."), + tr("You can still configure highlights for this device only in " + "%1.").arg(localHighlightsName)); + + QMessageBox::warning(this, + tr("Remote Highlights unsupported"), + remoteHighlightsMsgText); +} + void CoreHighlightSettingsPage::importRules() { NotificationSettings notificationSettings; + const auto localHighlightList = notificationSettings.highlightList(); + + // Re-use translations of "Legacy/Local Highlights" as this is a word-for-word reference, + // forcing all spaces to non-breaking + QString localHighlightsName; + if (Quassel::runMode() == Quassel::Monolithic) { + localHighlightsName = tr("Legacy Highlights").replace(" ", " "); + } else { + localHighlightsName = tr("Local Highlights").replace(" ", " "); + } + + if (localHighlightList.count() == 0) { + // No highlight rules exist to import, do nothing + QMessageBox::information(this, + tr("No highlights to import"), + tr("No highlight rules in %1." + ).arg(localHighlightsName)); + return; + } + + int ret = QMessageBox::question(this, + tr("Import highlights?"), + tr("Import all highlight rules from %1?" + ).arg(localHighlightsName), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + + if (ret != QMessageBox::Yes) { + // Only two options, Yes or No, return if not Yes + return; + } + auto clonedManager = HighlightRuleManager(); clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap()); @@ -559,6 +718,7 @@ void CoreHighlightSettingsPage::importRules() { auto highlightRule = variant.toMap(); clonedManager.addHighlightRule( + clonedManager.nextId(), highlightRule["Name"].toString(), highlightRule["RegEx"].toBool(), highlightRule["CS"].toBool(), @@ -572,8 +732,16 @@ void CoreHighlightSettingsPage::importRules() { Client::highlightRuleManager()->requestUpdate(clonedManager.toVariantMap()); setChangedState(false); load(); + + // Give a heads-up that all succeeded + QMessageBox::information(this, + tr("Imported highlights"), + tr("%1 highlight rules successfully imported." + ).arg(QString::number(localHighlightList.count()))); } bool CoreHighlightSettingsPage::isSelectable() const { - return Client::isConnected() && Client::isCoreFeatureEnabled(Quassel::Feature::CoreSideHighlights); + return Client::isConnected(); + // We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show + // a friendly error message. }