Implement UI for core-side highlights
[quassel.git] / src / qtui / settingspages / corehighlightsettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2016 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
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.                                           *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
21 #include "corehighlightsettingspage.h"
22
23 #include "qtui.h"
24 #include "uisettings.h"
25
26 #include <QHeaderView>
27 #include <client.h>
28
29 CoreHighlightSettingsPage::CoreHighlightSettingsPage(QWidget *parent)
30     : SettingsPage(tr("Interface"), tr("Core-Side Highlights"), parent)
31 {
32     ui.setupUi(this);
33     ui.highlightTable->verticalHeader()->hide();
34     ui.highlightTable->setShowGrid(false);
35
36     ui.highlightTable->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setToolTip("<b>RegEx</b>: This option determines if the highlight rule should be interpreted as a <b>regular expression</b> or just as a keyword.");
37     ui.highlightTable->horizontalHeaderItem(CoreHighlightSettingsPage::RegExColumn)->setWhatsThis("<b>RegEx</b>: This option determines if the highlight rule should be interpreted as a <b>regular expression</b> or just as a keyword.");
38
39     ui.highlightTable->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setToolTip("<b>CS</b>: This option determines if the highlight rule should be interpreted <b>case sensitive</b>.");
40     ui.highlightTable->horizontalHeaderItem(CoreHighlightSettingsPage::CsColumn)->setWhatsThis("<b>CS</b>: This option determines if the highlight rule should be interpreted <b>case sensitive</b>.");
41
42     ui.highlightTable->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setToolTip("<b>Channel</b>: This regular expression determines for which <b>channels</b> the highlight rule works. Leave blank to match any channel. Put <b>!</b> in the beginning to negate. Case insensitive.");
43     ui.highlightTable->horizontalHeaderItem(CoreHighlightSettingsPage::ChanColumn)->setWhatsThis("<b>Channel</b>: This regular expression determines for which <b>channels</b> the highlight rule works. Leave blank to match any channel. Put <b>!</b> in the beginning to negate. Case insensitive.");
44
45 #if QT_VERSION < 0x050000
46     ui.highlightTable->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
47     ui.highlightTable->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
48     ui.highlightTable->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
49     ui.highlightTable->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
50     ui.highlightTable->horizontalHeader()->setResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
51 #else
52     ui.highlightTable->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::NameColumn, QHeaderView::Stretch);
53     ui.highlightTable->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
54     ui.highlightTable->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
55     ui.highlightTable->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
56     ui.highlightTable->horizontalHeader()->setSectionResizeMode(CoreHighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
57 #endif
58
59     connect(ui.add, SIGNAL(clicked(bool)), this, SLOT(addNewRow()));
60     connect(ui.remove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedRows()));
61     //TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
62     connect(ui.highlightTable, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(selectRow(QTableWidgetItem *)));
63
64     connect(ui.highlightAllNicks, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
65     connect(ui.highlightCurrentNick, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
66     connect(ui.highlightNoNick, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
67     connect(ui.nicksCaseSensitive, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
68     connect(ui.add, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
69     connect(ui.remove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
70     connect(ui.highlightTable, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableChanged(QTableWidgetItem *)));
71
72     connect(Client::instance(), SIGNAL(connected()), this, SLOT(clientConnected()));
73 }
74
75 void CoreHighlightSettingsPage::clientConnected()
76 {
77     connect(Client::highlightRuleManager(), SIGNAL(updated()), SLOT(revert()));
78 }
79
80
81 void CoreHighlightSettingsPage::revert()
82 {
83     qWarning() << "revert()";
84
85     if (!hasChanged())
86         return;
87
88     setChangedState(false);
89     load();
90 }
91
92
93 bool CoreHighlightSettingsPage::hasDefaults() const
94 {
95     return true;
96 }
97
98
99 void CoreHighlightSettingsPage::defaults()
100 {
101     ui.highlightCurrentNick->setChecked(true);
102     ui.nicksCaseSensitive->setChecked(false);
103     emptyTable();
104
105     widgetHasChanged();
106 }
107
108
109 void CoreHighlightSettingsPage::addNewRow(QString name, bool regex, bool cs, bool enable, QString chanName, bool self)
110 {
111     ui.highlightTable->setRowCount(ui.highlightTable->rowCount()+1);
112
113     auto *nameItem = new QTableWidgetItem(name);
114
115     auto *regexItem = new QTableWidgetItem("");
116     if (regex)
117         regexItem->setCheckState(Qt::Checked);
118     else
119         regexItem->setCheckState(Qt::Unchecked);
120     regexItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable);
121
122     auto *csItem = new QTableWidgetItem("");
123     if (cs)
124         csItem->setCheckState(Qt::Checked);
125     else
126         csItem->setCheckState(Qt::Unchecked);
127     csItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable);
128
129     auto *enableItem = new QTableWidgetItem("");
130     if (enable)
131         enableItem->setCheckState(Qt::Checked);
132     else
133         enableItem->setCheckState(Qt::Unchecked);
134     enableItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable);
135
136     auto *chanNameItem = new QTableWidgetItem(chanName);
137
138     int lastRow = ui.highlightTable->rowCount()-1;
139     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
140     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
141     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
142     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
143     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
144
145     if (!self)
146         ui.highlightTable->setCurrentItem(nameItem);
147
148     highlightList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, chanName);
149 }
150
151
152 void CoreHighlightSettingsPage::removeSelectedRows()
153 {
154     QList<int> selectedRows;
155     QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
156     foreach(QTableWidgetItem *selectedItem, selectedItemList) {
157         selectedRows.append(selectedItem->row());
158     }
159     qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
160     int lastRow = -1;
161     foreach(int row, selectedRows) {
162         if (row != lastRow) {
163             ui.highlightTable->removeRow(row);
164             highlightList.removeAt(row);
165         }
166         lastRow = row;
167     }
168 }
169
170
171 void CoreHighlightSettingsPage::selectRow(QTableWidgetItem *item)
172 {
173     int row = item->row();
174     bool selected = item->isSelected();
175     ui.highlightTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, CoreHighlightSettingsPage::ColumnCount-1), selected);
176 }
177
178
179 void CoreHighlightSettingsPage::emptyTable()
180 {
181     // ui.highlight and highlightList should have the same size, but just to make sure.
182     if (ui.highlightTable->rowCount() != highlightList.size()) {
183         qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
184     }
185     while (ui.highlightTable->rowCount()) {
186         ui.highlightTable->removeRow(0);
187     }
188     while (highlightList.size()) {
189         highlightList.removeLast();
190     }
191 }
192
193
194 void CoreHighlightSettingsPage::tableChanged(QTableWidgetItem *item)
195 {
196     if (item->row()+1 > highlightList.size())
197         return;
198
199     auto highlightRule = highlightList.value(item->row());
200
201
202     switch (item->column())
203     {
204     case CoreHighlightSettingsPage::NameColumn:
205         if (item->text() == "")
206             item->setText(tr("this shouldn't be empty"));
207         highlightRule.name = item->text();
208         break;
209     case CoreHighlightSettingsPage::RegExColumn:
210         highlightRule.isRegEx = (item->checkState() == Qt::Checked);
211         break;
212     case CoreHighlightSettingsPage::CsColumn:
213         highlightRule.isCaseSensitive = (item->checkState() == Qt::Checked);
214         break;
215     case CoreHighlightSettingsPage::EnableColumn:
216         highlightRule.isEnabled = (item->checkState() == Qt::Checked);
217         break;
218     case CoreHighlightSettingsPage::ChanColumn:
219         if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
220             item->setText("");
221         highlightRule.chanName = item->text();
222         break;
223     }
224     highlightList[item->row()] = highlightRule;
225     emit widgetHasChanged();
226 }
227
228
229 void CoreHighlightSettingsPage::load()
230 {
231     emptyTable();
232
233     auto ruleManager = Client::highlightRuleManager();
234     for (HighlightRuleManager::HighlightRule rule : ruleManager->highlightRuleList()) {
235         addNewRow(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, rule.chanName);
236     }
237
238     switch (ruleManager->highlightNick())
239     {
240     case HighlightRuleManager::NoNick:
241         ui.highlightNoNick->setChecked(true);
242         break;
243     case HighlightRuleManager::CurrentNick:
244         ui.highlightCurrentNick->setChecked(true);
245         break;
246     case HighlightRuleManager::AllNicks:
247         ui.highlightAllNicks->setChecked(true);
248         break;
249     }
250     ui.nicksCaseSensitive->setChecked(ruleManager->nicksCaseSensitive());
251
252     setChangedState(false);
253     _initialized = true;
254 }
255
256 void CoreHighlightSettingsPage::save()
257 {
258     if (!hasChanged())
259         return;
260
261     if (!_initialized)
262         return;
263
264     auto ruleManager = Client::highlightRuleManager();
265     if (ruleManager == nullptr)
266         return;
267
268     auto clonedManager = HighlightRuleManager();
269     clonedManager.fromVariantMap(ruleManager->toVariantMap());
270     clonedManager.clear();
271
272     for (const HighlightRuleManager::HighlightRule &rule : highlightList) {
273         clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isRegEx, rule.chanName);
274     }
275
276     HighlightRuleManager::HighlightNickType highlightNickType = HighlightRuleManager::NoNick;
277     if (ui.highlightCurrentNick->isChecked())
278         highlightNickType = HighlightRuleManager::CurrentNick;
279     if (ui.highlightAllNicks->isChecked())
280         highlightNickType = HighlightRuleManager::AllNicks;
281
282
283     clonedManager.setHighlightNick(highlightNickType);
284     clonedManager.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
285
286     ruleManager->requestUpdate(clonedManager.toVariantMap());
287     setChangedState(false);
288     load();
289 }
290
291
292 void CoreHighlightSettingsPage::widgetHasChanged()
293 {
294     setChangedState(true);
295 }