#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);
connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected()));
// Warning icon
- ui.coreUnsupportedIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(16));
+ 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 <i>%1</i>.")
+ .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 <i>%1</i>.")
+ .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);
}
}
+
void CoreHighlightSettingsPage::setupRuleTable(QTableWidget *table) const
{
table->verticalHeader()->hide();
table->setShowGrid(false);
- table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip(
- tr("<b>RegEx</b>: This option determines if the highlight rule should be "
- "interpreted as a <b>regular expression</b> or just as a keyword."));
- table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis(
- table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->toolTip());
-
- table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip(
- tr("<b>CS</b>: This option determines if the highlight rule should be interpreted "
- "<b>case sensitive</b>."));
- table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis(
- table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->toolTip());
-
- table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip(
- tr("<p><b>Channel</b>: Semicolon separated list of channel names.</p>"
- "<p><i>Example:</i><br />"
- "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
- "would match on #foobar and on any channel starting with <i>#quassel</i> except "
- "for <i>#quasseldroid</i><br />"
- "<p>If only inverted names are specified, it will match anything except for "
- "what's specified (implicit wildcard).</p>"
- "<p><i>Example:</i><br />"
- "<i>!#quassel*; !#foobar</i><br />"
- "would match anything except for #foobar or any channel starting with "
- "<i>#quassel</i></p>"));
- table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis(
- table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->toolTip());
+ setupTableTooltips(table->horizontalHeaderItem(CoreHighlightSettingsPage::EnableColumn),
+ table->horizontalHeaderItem(CoreHighlightSettingsPage::NameColumn),
+ table->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn),
+ table->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn),
+ table->horizontalHeaderItem(CoreHighlightSettingsPage::SenderColumn),
+ table->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn));
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
+ table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
table->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
#else
table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
+ table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::SenderColumn, QHeaderView::ResizeToContents);
table->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
#endif
}
+
+QString CoreHighlightSettingsPage::getTableTooltip(column tableColumn) const
+{
+ switch (tableColumn) {
+ case CoreHighlightSettingsPage::EnableColumn:
+ return tr("Enable/disable this rule");
+
+ case CoreHighlightSettingsPage::NameColumn:
+ return tr("Phrase to match");
+
+ case CoreHighlightSettingsPage::RegExColumn:
+ return tr("<b>RegEx</b>: This option determines if the highlight rule, <i>Sender</i>, and "
+ "<i>Channel</i> should be interpreted as <b>regular expressions</b> or just as "
+ "keywords.");
+
+ case CoreHighlightSettingsPage::CsColumn:
+ return tr("<b>CS</b>: This option determines if the highlight rule, <i>Sender</i>, and "
+ "<i>Channel</i> should be interpreted <b>case sensitive</b>.");
+
+ case CoreHighlightSettingsPage::SenderColumn:
+ return tr("<p><b>Sender</b>: Semicolon separated list of <i>nick!ident@host</i> names, "
+ "leave blank to match any nickname.</p>"
+ "<p><i>Example:</i><br />"
+ "<i>Alice!*; Bob!*@example.com; Carol*!*; !Caroline!*</i><br />"
+ "would match on <i>Alice</i>, <i>Bob</i> with hostmask <i>example.com</i>, and "
+ "any nickname starting with <i>Carol</i> except for <i>Caroline</i><br />"
+ "<p>If only inverted names are specified, it will match anything except for "
+ "what's specified (implicit wildcard).</p>"
+ "<p><i>Example:</i><br />"
+ "<i>!Announce*!*; !Wheatley!aperture@*</i><br />"
+ "would match anything except for <i>Wheatley</i> with ident <i>aperture</i> or "
+ "any nickname starting with <i>Announce</i></p>");
+
+ case CoreHighlightSettingsPage::ChanColumn:
+ return tr("<p><b>Channel</b>: Semicolon separated list of channel names, leave blank to "
+ "match any name.</p>"
+ "<p><i>Example:</i><br />"
+ "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
+ "would match on <i>#foobar</i> and any channel starting with <i>#quassel</i> "
+ "except for <i>#quasseldroid</i><br />"
+ "<p>If only inverted names are specified, it will match anything except for "
+ "what's specified (implicit wildcard).</p>"
+ "<p><i>Example:</i><br />"
+ "<i>!#quassel*; !#foobar</i><br />"
+ "would match anything except for <i>#foobar</i> or any channel starting with "
+ "<i>#quassel</i></p>");
+
+ default:
+ // This shouldn't happen
+ return "Invalid column type in CoreHighlightSettingsPage::getTableTooltip()";
+ }
+}
+
+
+void CoreHighlightSettingsPage::setupTableTooltips(QWidget *enableWidget, QWidget *nameWidget,
+ QWidget *regExWidget, QWidget *csWidget,
+ QWidget *senderWidget, QWidget *chanWidget) const
+{
+ // Make sure everything's valid
+ Q_ASSERT(enableWidget);
+ Q_ASSERT(nameWidget);
+ Q_ASSERT(regExWidget);
+ Q_ASSERT(csWidget);
+ Q_ASSERT(senderWidget);
+ Q_ASSERT(chanWidget);
+
+ // Set tooltips and "What's this?" prompts
+ // Enabled
+ enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
+ enableWidget->setWhatsThis(enableWidget->toolTip());
+
+ // Name
+ nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
+ nameWidget->setWhatsThis(nameWidget->toolTip());
+
+ // RegEx enabled
+ regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
+ regExWidget->setWhatsThis(regExWidget->toolTip());
+
+ // Case-sensitivity
+ csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
+ csWidget->setWhatsThis(csWidget->toolTip());
+
+ // Sender
+ senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
+ senderWidget->setWhatsThis(senderWidget->toolTip());
+
+ // Channel/buffer name
+ chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
+ chanWidget->setWhatsThis(chanWidget->toolTip());
+}
+
+
+void CoreHighlightSettingsPage::setupTableTooltips(QTableWidgetItem *enableWidget,
+ QTableWidgetItem *nameWidget,
+ QTableWidgetItem *regExWidget,
+ QTableWidgetItem *csWidget,
+ QTableWidgetItem *senderWidget,
+ QTableWidgetItem *chanWidget) const
+{
+ // Make sure everything's valid
+ Q_ASSERT(enableWidget);
+ Q_ASSERT(nameWidget);
+ Q_ASSERT(regExWidget);
+ Q_ASSERT(csWidget);
+ Q_ASSERT(senderWidget);
+ Q_ASSERT(chanWidget);
+
+ // Set tooltips and "What's this?" prompts
+ // Enabled
+ enableWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::EnableColumn));
+ enableWidget->setWhatsThis(enableWidget->toolTip());
+
+ // Name
+ nameWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::NameColumn));
+ nameWidget->setWhatsThis(nameWidget->toolTip());
+
+ // RegEx enabled
+ regExWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::RegExColumn));
+ regExWidget->setWhatsThis(regExWidget->toolTip());
+
+ // Case-sensitivity
+ csWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::CsColumn));
+ csWidget->setWhatsThis(csWidget->toolTip());
+
+ // Sender
+ senderWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::SenderColumn));
+ senderWidget->setWhatsThis(senderWidget->toolTip());
+
+ // Channel/buffer name
+ chanWidget->setToolTip(getTableTooltip(CoreHighlightSettingsPage::ChanColumn));
+ chanWidget->setWhatsThis(chanWidget->toolTip());
+}
+
+
void CoreHighlightSettingsPage::updateCoreSupportStatus(bool state)
{
// Assume connected state as enforced by the settings page UI
}
}
+
void CoreHighlightSettingsPage::clientConnected()
{
connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
}
+
void CoreHighlightSettingsPage::revert()
{
if (!hasChanged())
load();
}
+
bool CoreHighlightSettingsPage::hasDefaults() const
{
return true;
}
+
void CoreHighlightSettingsPage::defaults()
{
int highlightNickType = HighlightRuleManager::HighlightNickType::CurrentNick;
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("");
enableItem->setCheckState(Qt::Unchecked);
enableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
- auto *chanNameItem = new QTableWidgetItem(chanName);
-
auto *senderItem = new QTableWidgetItem(sender);
- enableItem->setToolTip(tr("Enable/disable this rule"));
- nameItem->setToolTip(tr("Phrase to match"));
- regexItem->setToolTip(
- tr("<b>RegEx</b>: This option determines if the highlight rule should be "
- "interpreted as a <b>regular expression</b> or just as a keyword."));
- csItem->setToolTip(
- tr("<b>CS</b>: This option determines if the highlight rule should be interpreted "
- "<b>case sensitive</b>."));
- senderItem->setToolTip(
- tr("<b>Sender</b>: This option specifies which sender to match. Leave blank to "
- "match any nickname."));
- chanNameItem->setToolTip(
- tr("<p><b>Channel</b>: Semicolon separated list of channel names.</p>"
- "<p><i>Example:</i><br />"
- "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
- "would match on #foobar and on any channel starting with <i>#quassel</i> except "
- "for <i>#quasseldroid</i><br />"
- "<p>If only inverted names are specified, it will match anything except for "
- "what's specified (implicit wildcard).</p>"
- "<p><i>Example:</i><br />"
- "<i>!#quassel*; !#foobar</i><br />"
- "would match anything except for #foobar or any channel starting with "
- "<i>#quassel</i></p>"));
+ auto *chanNameItem = new QTableWidgetItem(chanName);
+
+ setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
int lastRow = ui.highlightTable->rowCount() - 1;
ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
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("");
auto *senderItem = new QTableWidgetItem(sender);
- enableItem->setToolTip(tr("Enable/disable this rule"));
- nameItem->setToolTip(tr("Phrase to match"));
- regexItem->setToolTip(
- tr("<b>RegEx</b>: This option determines if the highlight rule should be "
- "interpreted as a <b>regular expression</b> or just as a keyword."));
- csItem->setToolTip(
- tr("<b>CS</b>: This option determines if the highlight rule should be interpreted "
- "<b>case sensitive</b>."));
- senderItem->setToolTip(
- tr("<b>Sender</b>: This option specifies which sender nicknames match. Leave "
- "blank to match any nickname."));
- chanNameItem->setToolTip(
- tr("<p><b>Channel</b>: Semicolon separated list of channel names.</p>"
- "<p><i>Example:</i><br />"
- "<i>#quassel*; #foobar; !#quasseldroid</i><br />"
- "would match on #foobar and on any channel starting with <i>#quassel</i> except "
- "for <i>#quasseldroid</i><br />"
- "<p>If only inverted names are specified, it will match anything except for "
- "what's specified (implicit wildcard).</p>"
- "<p><i>Example:</i><br />"
- "<i>!#quassel*; !#foobar</i><br />"
- "would match anything except for #foobar or any channel starting with "
- "<i>#quassel</i></p>"));
+ setupTableTooltips(enableItem, nameItem, regexItem, csItem, senderItem, chanNameItem);
int lastRow = ui.ignoredTable->rowCount() - 1;
ui.ignoredTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
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()
{
QList<int> selectedRows;
}
}
+
void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
{
QList<int> selectedRows;
}
}
-void CoreHighlightSettingsPage::highlightNicksChanged(const int index) {
+
+void CoreHighlightSettingsPage::highlightNicksChanged(const int index)
+{
// Only allow toggling "Case sensitive" when a nickname will be highlighted
auto highlightNickType = ui.highlightNicksComboBox->itemData(index).value<int>();
ui.nicksCaseSensitive->setEnabled(highlightNickType != HighlightRuleManager::NoNick);
}
+
void CoreHighlightSettingsPage::selectHighlightRow(QTableWidgetItem *item)
{
int row = item->row();
selected);
}
+
void CoreHighlightSettingsPage::selectIgnoredRow(QTableWidgetItem *item)
{
int row = item->row();
selected);
}
+
void CoreHighlightSettingsPage::emptyHighlightTable()
{
// ui.highlight and highlightList should have the same size, but just to make sure.
highlightList.clear();
}
+
void CoreHighlightSettingsPage::emptyIgnoredTable()
{
// ui.highlight and highlightList should have the same size, but just to make sure.
ignoredList.clear();
}
+
void CoreHighlightSettingsPage::highlightTableChanged(QTableWidgetItem *item)
{
if (item->row() + 1 > highlightList.size())
emit widgetHasChanged();
}
+
void CoreHighlightSettingsPage::ignoredTableChanged(QTableWidgetItem *item)
{
if (item->row() + 1 > ignoredList.size())
emit widgetHasChanged();
}
+
void CoreHighlightSettingsPage::load()
{
emptyHighlightTable();
for (auto &rule : ruleManager->highlightRuleList()) {
if (rule.isInverse) {
addNewIgnoredRow(rule.isEnabled,
+ rule.id,
rule.name,
rule.isRegEx,
rule.isCaseSensitive,
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);
}
}
}
}
+
void CoreHighlightSettingsPage::save()
{
if (!hasChanged())
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);
}
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
remoteHighlightsMsgText);
}
-void CoreHighlightSettingsPage::importRules() {
+
+void CoreHighlightSettingsPage::importRules()
+{
NotificationSettings notificationSettings;
const auto localHighlightList = notificationSettings.highlightList();
- // 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(" ", " ");
+ // 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 local highlights"),
+ tr("No highlights to import"),
tr("No highlight rules in <i>%1</i>."
).arg(localHighlightsName));
return;
}
int ret = QMessageBox::question(this,
- tr("Import local highlights?"),
+ tr("Import highlights?"),
tr("Import all highlight rules from <i>%1</i>?"
).arg(localHighlightsName),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::No);
- if (ret == QMessageBox::No) {
- // Only two options, Yes or No, just return if No
+ if (ret != QMessageBox::Yes) {
+ // Only two options, Yes or No, return if not Yes
return;
}
+ if (hasChanged()) {
+ // Save existing changes first to avoid overwriting them
+ save();
+ }
+
auto clonedManager = HighlightRuleManager();
clonedManager.fromVariantMap(Client::highlightRuleManager()->toVariantMap());
auto highlightRule = variant.toMap();
clonedManager.addHighlightRule(
+ clonedManager.nextId(),
highlightRule["Name"].toString(),
highlightRule["RegEx"].toBool(),
highlightRule["CS"].toBool(),
// Give a heads-up that all succeeded
QMessageBox::information(this,
- tr("Imported local highlights"),
+ tr("Imported highlights"),
tr("%1 highlight rules successfully imported."
).arg(QString::number(localHighlightList.count())));
}
-bool CoreHighlightSettingsPage::isSelectable() const {
+
+bool CoreHighlightSettingsPage::isSelectable() const
+{
return Client::isConnected();
// We check for Quassel::Feature::CoreSideHighlights when loading this page, allowing us to show
// a friendly error message.