Initial Channel specific highlights feature implementation
[quassel.git] / src / qtui / settingspages / highlightsettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-09 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 Highlight Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
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 Highlight Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Highlight Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "highlightsettingspage.h"
22
23 #include "qtui.h"
24 #include "uisettings.h"
25
26 #include <QHeaderView>
27
28
29 HighlightSettingsPage::HighlightSettingsPage(QWidget *parent)
30   : SettingsPage(tr("Interface"), tr("Highlight"), parent) {
31   ui.setupUi(this);
32   ui.highlightTable->verticalHeader()->hide();
33   ui.highlightTable->setShowGrid(false);
34
35   ui.highlightTable->horizontalHeaderItem(HighlightSettingsPage::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.");
36   ui.highlightTable->horizontalHeaderItem(HighlightSettingsPage::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.");
37
38   ui.highlightTable->horizontalHeaderItem(HighlightSettingsPage::CsColumn)->setToolTip("<b>CS</b>: This option determines if the highlight rule should be interpreted <b>case sensitive</b>.");
39   ui.highlightTable->horizontalHeaderItem(HighlightSettingsPage::CsColumn)->setWhatsThis("<b>CS</b>: This option determines if the highlight rule should be interpreted <b>case sensitive</b>.");
40
41   ui.highlightTable->horizontalHeaderItem(HighlightSettingsPage::ChanColumn)->setToolTip("<b>Chan</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.");
42   ui.highlightTable->horizontalHeaderItem(HighlightSettingsPage::ChanColumn)->setWhatsThis("<b>Chan</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
44   ui.highlightTable->horizontalHeader()->setResizeMode(HighlightSettingsPage::NameColumn, QHeaderView::Stretch);
45   ui.highlightTable->horizontalHeader()->setResizeMode(HighlightSettingsPage::RegExColumn, QHeaderView::ResizeToContents);
46   ui.highlightTable->horizontalHeader()->setResizeMode(HighlightSettingsPage::CsColumn, QHeaderView::ResizeToContents);
47   ui.highlightTable->horizontalHeader()->setResizeMode(HighlightSettingsPage::EnableColumn, QHeaderView::ResizeToContents);
48   ui.highlightTable->horizontalHeader()->setResizeMode(HighlightSettingsPage::ChanColumn, QHeaderView::ResizeToContents);
49
50   connect(ui.add, SIGNAL(clicked(bool)), this, SLOT(addNewRow()));
51   connect(ui.remove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedRows()));
52   //TODO: search for a better signal (one that emits everytime a selection has been changed for one item)
53   connect(ui.highlightTable, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(selectRow(QTableWidgetItem *)));
54
55   connect(ui.highlightAllNicks, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
56   connect(ui.highlightCurrentNick, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
57   connect(ui.highlightNoNick, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
58   connect(ui.nicksCaseSensitive, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
59   connect(ui.add, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
60   connect(ui.remove, SIGNAL(clicked()), this, SLOT(widgetHasChanged()));
61   connect(ui.highlightTable, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableChanged(QTableWidgetItem *)));
62 }
63
64 bool HighlightSettingsPage::hasDefaults() const {
65   return true;
66 }
67
68 void HighlightSettingsPage::defaults() {
69   ui.highlightCurrentNick->setChecked(true);
70   ui.nicksCaseSensitive->setChecked(false);
71   emptyTable();
72
73   widgetHasChanged();
74 }
75
76 void HighlightSettingsPage::addNewRow(QString name, bool regex, bool cs, bool enable, QString chanName) {
77   ui.highlightTable->setRowCount(ui.highlightTable->rowCount()+1);
78
79   QTableWidgetItem *nameItem = new QTableWidgetItem(name);
80
81   QTableWidgetItem *regexItem = new QTableWidgetItem("");
82   if(regex)
83     regexItem->setCheckState(Qt::Checked);
84   else
85     regexItem->setCheckState(Qt::Unchecked);
86   regexItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable);
87
88   QTableWidgetItem *csItem = new QTableWidgetItem("");
89   if(cs)
90     csItem->setCheckState(Qt::Checked);
91   else
92     csItem->setCheckState(Qt::Unchecked);
93   csItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable);
94
95   QTableWidgetItem *enableItem = new QTableWidgetItem("");
96   if(enable)
97     enableItem->setCheckState(Qt::Checked);
98   else
99     enableItem->setCheckState(Qt::Unchecked);
100   enableItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable);
101
102   QTableWidgetItem *chanNameItem = new QTableWidgetItem(chanName);
103
104   int lastRow = ui.highlightTable->rowCount()-1;
105   ui.highlightTable->setItem(lastRow, HighlightSettingsPage::NameColumn, nameItem);
106   ui.highlightTable->setItem(lastRow, HighlightSettingsPage::RegExColumn, regexItem);
107   ui.highlightTable->setItem(lastRow, HighlightSettingsPage::CsColumn, csItem);
108   ui.highlightTable->setItem(lastRow, HighlightSettingsPage::EnableColumn, enableItem);
109   ui.highlightTable->setItem(lastRow, HighlightSettingsPage::ChanColumn, chanNameItem);
110
111   QVariantMap highlightRule;
112   highlightRule["Name"] = name;
113   highlightRule["RegEx"] = regex;
114   highlightRule["CS"] = cs;
115   highlightRule["Enable"] = enable;
116   highlightRule["Chan"] = chanName;
117
118   highlightList.append(highlightRule);
119 }
120
121 void HighlightSettingsPage::removeSelectedRows() {
122   QList<int> selectedRows;
123   QList<QTableWidgetItem *> selectedItemList = ui.highlightTable->selectedItems();
124   foreach(QTableWidgetItem *selectedItem, selectedItemList) {
125     selectedRows.append(selectedItem->row());
126   }
127   qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
128   int lastRow = -1;
129   foreach(int row, selectedRows) {
130     if(row != lastRow) {
131       ui.highlightTable->removeRow(row);
132       highlightList.removeAt(row);
133     }
134     lastRow = row;
135   }
136 }
137
138 void HighlightSettingsPage::selectRow(QTableWidgetItem *item) {
139   int row = item->row();
140   bool selected = item->isSelected();
141   ui.highlightTable->setRangeSelected(QTableWidgetSelectionRange(row, 0, row, HighlightSettingsPage::ColumnCount-1), selected);
142 }
143
144 void HighlightSettingsPage::emptyTable() {
145   // ui.highlight and highlightList should have the same size, but just to make sure.
146   if(ui.highlightTable->rowCount() != highlightList.size()) {
147     qDebug() << "something is wrong: ui.highlight and highlightList don't have the same size!";
148   }
149   while(ui.highlightTable->rowCount()) {
150     ui.highlightTable->removeRow(0);
151   }
152   while(highlightList.size()) {
153         highlightList.removeLast();
154   }
155 }
156
157 void HighlightSettingsPage::tableChanged(QTableWidgetItem *item) {
158   if(item->row()+1 > highlightList.size())
159     return;
160
161   QVariantMap highlightRule = highlightList.value(item->row()).toMap();
162
163   switch(item->column())
164   {
165     case HighlightSettingsPage::NameColumn:
166       if(item->text() == "")
167         item->setText(tr("this shouldn't be empty"));
168       highlightRule["Name"] = item->text();
169       break;
170     case HighlightSettingsPage::RegExColumn:
171       highlightRule["RegEx"] = (item->checkState() == Qt::Checked);
172       break;
173     case HighlightSettingsPage::CsColumn:
174       highlightRule["CS"] = (item->checkState() == Qt::Checked);
175       break;
176     case HighlightSettingsPage::EnableColumn:
177       highlightRule["Enable"] = (item->checkState() == Qt::Checked);
178       break;
179     case HighlightSettingsPage::ChanColumn:
180       if(item->text().size() > 0 && item->text().trimmed().size() == 0)
181         item->setText("");
182       highlightRule["Chan"] = item->text();
183       break;
184   }
185   highlightList[item->row()] = highlightRule;
186   emit widgetHasChanged();
187 }
188
189 void HighlightSettingsPage::load() {
190   NotificationSettings notificationSettings;
191
192   emptyTable();
193
194   foreach(QVariant highlight, notificationSettings.highlightList()) {
195     QVariantMap highlightRule = highlight.toMap();
196     QString name = highlightRule["Name"].toString();
197     bool regex = highlightRule["RegEx"].toBool();
198     bool cs = highlightRule["CS"].toBool();
199     bool enable = highlightRule["Enable"].toBool();
200     QString chanName = highlightRule["Chan"].toString();
201
202     addNewRow(name, regex, cs, enable, chanName);
203   }
204
205   switch(notificationSettings.highlightNick())
206   {
207     case NotificationSettings::NoNick:
208       ui.highlightNoNick->setChecked(true);
209       break;
210     case NotificationSettings::CurrentNick:
211       ui.highlightCurrentNick->setChecked(true);
212       break;
213     case NotificationSettings::AllNicks:
214       ui.highlightAllNicks->setChecked(true);
215       break;
216   }
217   ui.nicksCaseSensitive->setChecked(notificationSettings.nicksCaseSensitive());
218
219   setChangedState(false);
220 }
221
222 void HighlightSettingsPage::save() {
223   NotificationSettings notificationSettings;
224   notificationSettings.setHighlightList(highlightList);
225
226   NotificationSettings::HighlightNickType highlightNickType;
227   if(ui.highlightNoNick->isChecked())
228     highlightNickType = NotificationSettings::NoNick;
229   if(ui.highlightCurrentNick->isChecked())
230     highlightNickType = NotificationSettings::CurrentNick;
231   if(ui.highlightAllNicks->isChecked())
232     highlightNickType = NotificationSettings::AllNicks;
233
234   notificationSettings.setHighlightNick(highlightNickType);
235   notificationSettings.setNicksCaseSensitive(ui.nicksCaseSensitive->isChecked());
236
237   load();
238   setChangedState(false);
239 }
240
241 void HighlightSettingsPage::widgetHasChanged() {
242   bool changed = testHasChanged();
243   if(changed != hasChanged()) setChangedState(changed);
244 }
245
246 bool HighlightSettingsPage::testHasChanged() {
247   NotificationSettings notificationSettings;
248
249   NotificationSettings::HighlightNickType highlightNickType;
250   if(ui.highlightNoNick->isChecked())
251     highlightNickType = NotificationSettings::NoNick;
252   if(ui.highlightCurrentNick->isChecked())
253     highlightNickType = NotificationSettings::CurrentNick;
254   if(ui.highlightAllNicks->isChecked())
255     highlightNickType = NotificationSettings::AllNicks;
256
257   if(notificationSettings.highlightNick() != highlightNickType) return true;
258   if(notificationSettings.nicksCaseSensitive() != ui.nicksCaseSensitive->isChecked()) return true;
259
260   if(notificationSettings.highlightList() != highlightList) return true;
261
262   return false;
263 }