1 /***************************************************************************
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 3 of the License, or *
6 * (at your option) any later version. *
7 * *
8 ***************************************************************************/
9
10 #include "SearchBlacklistDialog.h"
11 #include "SearchBlacklist.h"
12 #include "WulforUtil.h"
13
14 #include <QComboBox>
15 #include <QLineEdit>
16 #include <QMenu>
17 #include <QItemSelectionModel>
18 #include <QResizeEvent>
19
SearchBlackListDialog(QWidget * parent)20 SearchBlackListDialog::SearchBlackListDialog(QWidget *parent): QDialog(parent){
21 setupUi(this);
22
23 model = new SearchBlackListModel();
24 treeView_RULES->setModel(model);
25 treeView_RULES->setItemDelegate(new SearchBlackListDelegate(this));
26 treeView_RULES->setContextMenuPolicy(Qt::CustomContextMenu);
27 treeView_RULES->setSortingEnabled(true);
28 treeView_RULES->sortByColumn(COLUMN_SBL_KEY, Qt::AscendingOrder);
29
30 connect(treeView_RULES, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu()));
31 connect(this, SIGNAL(accepted()), this, SLOT(ok()));
32 }
33
~SearchBlackListDialog()34 SearchBlackListDialog::~SearchBlackListDialog(){
35 model->deleteLater();
36 }
37
ok()38 void SearchBlackListDialog::ok(){
39 model->save();
40 }
41
resizeEvent(QResizeEvent * e)42 void SearchBlackListDialog::resizeEvent(QResizeEvent *e){
43 e->accept();
44
45 treeView_RULES->resizeColumnToContents(COLUMN_SBL_TYPE);
46
47 int sblTypeWidth = treeView_RULES->columnWidth(COLUMN_SBL_TYPE);
48 int sblKeyWidth = treeView_RULES->contentsRect().width() - sblTypeWidth;
49
50 treeView_RULES->setColumnWidth(COLUMN_SBL_KEY, sblKeyWidth);
51 }
52
slotContextMenu()53 void SearchBlackListDialog::slotContextMenu(){
54 QItemSelectionModel *s_m = treeView_RULES->selectionModel();
55 QModelIndexList indexes = s_m->selectedRows(0);
56
57 QMenu *menu = new QMenu(this);
58 QAction *add = new QAction(WICON(WulforUtil::eiEDITADD), tr("Add new"), NULL);
59 QAction *rem = new QAction(WICON(WulforUtil::eiEDITDELETE), tr("Remove"), NULL);
60
61 menu->addActions(QList<QAction*>() << add << rem);
62
63 QAction *ret = menu->exec(QCursor::pos());
64
65 menu->deleteLater();
66
67 if (ret == add){
68 s_m->select(model->addEmptyItem(), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
69 }
70 else if (ret && !indexes.isEmpty()){
71 for (const auto &index : indexes){
72 SearchBlackListItem *i = reinterpret_cast<SearchBlackListItem*>(index.internalPointer());
73
74 if (!i)
75 continue;
76
77 i->parent()->childItems.removeAt(i->row());
78 }
79
80 model->repaint();
81 }
82 }
83
SearchBlackListModel(QObject * parent)84 SearchBlackListModel::SearchBlackListModel(QObject * parent) :
85 QAbstractItemModel(parent),
86 sortColumn(COLUMN_SBL_KEY)
87 {
88 rootItem = new SearchBlackListItem(NULL);
89
90 SearchBlacklist *SB = SearchBlacklist::getInstance();
91
92 QList<QString> names = SB->getList(SearchBlacklist::NAME);
93 QList<QString> tths = SB->getList(SearchBlacklist::TTH);
94
95 for (const auto &name : names){
96 SearchBlackListItem * item = new SearchBlackListItem(rootItem);
97 item->title = name;
98 item->argument = SearchBlacklist::NAME;
99
100 rootItem->appendChild(item);
101 }
102
103 for (const auto &tth : tths){
104 SearchBlackListItem * item = new SearchBlackListItem(rootItem);
105 item->title = tth;
106 item->argument = SearchBlacklist::TTH;
107
108 rootItem->appendChild(item);
109 }
110
111 sortColumn = -1;
112 }
113
114
~SearchBlackListModel()115 SearchBlackListModel::~SearchBlackListModel() {
116 delete rootItem;
117 }
118
save()119 void SearchBlackListModel::save(){
120 QList<QString> names;
121 QList<QString> tths;
122
123 for (const auto &item : rootItem->childItems){
124 QList<QString> &l = (item->argument == SearchBlacklist::NAME? names : tths);
125
126 l.push_back(item->title);
127 }
128
129 SearchBlacklist *SB = SearchBlacklist::getInstance();
130 SB->setList(SearchBlacklist::NAME, names);
131 SB->setList(SearchBlacklist::TTH, tths);
132 }
133
rowCount(const QModelIndex &) const134 int SearchBlackListModel::rowCount(const QModelIndex & ) const {
135 return rootItem->childCount();
136 }
137
columnCount(const QModelIndex &) const138 int SearchBlackListModel::columnCount(const QModelIndex & ) const {
139 return 2;
140 }
141
flags(const QModelIndex & index) const142 Qt::ItemFlags SearchBlackListModel::flags(const QModelIndex &index) const {
143 if (!index.isValid())
144 return 0;
145
146 return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
147 }
148
data(const QModelIndex & index,int role) const149 QVariant SearchBlackListModel::data(const QModelIndex & index, int role) const {
150 if (!index.isValid())
151 return QVariant();
152
153 SearchBlackListItem * item = static_cast<SearchBlackListItem*>(index.internalPointer());
154
155 if (!item)
156 return QVariant();
157
158 switch (role){
159 case Qt::DisplayRole:
160 {
161 if (!index.column())
162 return item->title;
163 else
164 return (item->argument == SearchBlacklist::NAME? tr("Filename") : tr("TTH"));
165
166 break;
167 }
168 default:
169 break;
170 }
171
172 return QVariant();
173 }
174
175
headerData(int section,Qt::Orientation orientation,int role) const176 QVariant SearchBlackListModel::headerData(int section, Qt::Orientation orientation, int role) const {
177 if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) {
178 switch (section) {
179 case 0: return tr("Key");
180 case 1: return tr("Type");
181 }
182 }
183
184 return QVariant();
185 }
186
data(int column) const187 QVariant SearchBlackListItem::data(int column) const {
188 if (column == COLUMN_SBL_KEY && !childItems.isEmpty() && parentItem)
189 return childItems.size()+1;
190
191 switch(column){
192 case COLUMN_SBL_TYPE:
193 return QVariant (argument);
194 default:
195 return QVariant (title);
196 }
197 }
198
199 namespace {
200 template <Qt::SortOrder order>
201 struct Compare {
sort__anon9544dc530111::Compare202 void static sort(int col, QList<SearchBlackListItem*>& items) {
203 qStableSort(items.begin(), items.end(), getAttrComp(col));
204 }
205
insertSorted__anon9544dc530111::Compare206 void static insertSorted(int col, QList<SearchBlackListItem*>& items, SearchBlackListItem* item) {
207 auto it = qLowerBound(items.begin(), items.end(), item, getAttrComp(col));
208 items.insert(it, item);
209 }
210
211 private:
212 typedef bool (*AttrComp)(const SearchBlackListItem * l, const SearchBlackListItem * r);
getAttrComp__anon9544dc530111::Compare213 AttrComp static getAttrComp(int column) {
214 switch (column){
215 case COLUMN_SBL_TYPE:
216 return AttrCmp<COLUMN_SBL_TYPE>;
217 default:
218 return AttrCmp<COLUMN_SBL_KEY>;
219 }
220 }
221 template <int i>
AttrCmp__anon9544dc530111::Compare222 bool static AttrCmp(const SearchBlackListItem * l, const SearchBlackListItem * r) {
223 return Cmp(QString::localeAwareCompare(l->data(i).toString(), r->data(i).toString()), 0);
224 }
225 template <typename T, T (SearchBlackListItem::*attr)>
AttrCmp__anon9544dc530111::Compare226 bool static AttrCmp(const SearchBlackListItem * l, const SearchBlackListItem * r) {
227 return Cmp(l->*attr, r->*attr);
228 }
229 template <int i>
NumCmp__anon9544dc530111::Compare230 bool static NumCmp(const SearchBlackListItem * l, const SearchBlackListItem * r) {
231 return Cmp(l->data(i).toULongLong(), r->data(i).toULongLong());
232 }
233 template <typename T>
234 bool static Cmp(const T& l, const T& r);
235 };
236
237 template <> template <typename T>
Cmp(const T & l,const T & r)238 bool inline Compare<Qt::AscendingOrder>::Cmp(const T& l, const T& r) {
239 return l < r;
240 }
241
242 template <> template <typename T>
Cmp(const T & l,const T & r)243 bool inline Compare<Qt::DescendingOrder>::Cmp(const T& l, const T& r) {
244 return l > r;
245 }
246 } //namespace
247
sort(int column,Qt::SortOrder order)248 void SearchBlackListModel::sort(int column, Qt::SortOrder order) {
249 static int c = 0;
250
251 if (column < 0)
252 column = c;
253
254 emit layoutAboutToBeChanged();
255
256 if (order == Qt::AscendingOrder)
257 Compare<Qt::AscendingOrder>().sort(column, rootItem->childItems);
258 else if (order == Qt::DescendingOrder)
259 Compare<Qt::DescendingOrder>().sort(column, rootItem->childItems);
260
261 c = column;
262
263 emit layoutChanged();
264 }
265
index(int row,int column,const QModelIndex &) const266 QModelIndex SearchBlackListModel::index(int row, int column, const QModelIndex &) const {
267 if (row > (rootItem->childCount() - 1) || row < 0)
268 return QModelIndex();
269
270 return createIndex(row, column, rootItem->child(row));
271 }
272
parent(const QModelIndex &) const273 QModelIndex SearchBlackListModel::parent(const QModelIndex & ) const {
274 return QModelIndex();
275 }
276
addEmptyItem()277 QModelIndex SearchBlackListModel::addEmptyItem(){
278 SearchBlackListItem *item = new SearchBlackListItem(rootItem);
279 item->title = tr("Set text...");
280
281 rootItem->appendChild(item);
282
283 emit layoutChanged();
284
285 return createIndex(item->row(), 0, item);
286 }
287
getSortColumn() const288 int SearchBlackListModel::getSortColumn() const{
289 return sortColumn;
290 }
291
setSortColumn(int sc)292 void SearchBlackListModel::setSortColumn(int sc){
293 sortColumn = sc;
294 }
295
SearchBlackListItem(SearchBlackListItem * parent)296 SearchBlackListItem::SearchBlackListItem(SearchBlackListItem *parent) : argument(0), parentItem(parent)
297 {
298 }
299
~SearchBlackListItem()300 SearchBlackListItem::~SearchBlackListItem()
301 {
302 qDeleteAll(childItems);
303 }
304
appendChild(SearchBlackListItem * item)305 void SearchBlackListItem::appendChild(SearchBlackListItem *item) {
306 item->parentItem = this;
307 childItems.append(item);
308 }
309
child(int row)310 SearchBlackListItem *SearchBlackListItem::child(int row) {
311 return childItems.value(row);
312 }
313
childCount() const314 int SearchBlackListItem::childCount() const {
315 return childItems.count();
316 }
317
columnCount() const318 int SearchBlackListItem::columnCount() const {
319 return itemData.count();
320 }
parent()321 SearchBlackListItem *SearchBlackListItem::parent() {
322 return parentItem;
323 }
324
row() const325 int SearchBlackListItem::row() const {
326 if (parentItem)
327 return parentItem->childItems.indexOf(const_cast<SearchBlackListItem*>(this));
328
329 return 0;
330 }
331
SearchBlackListDelegate(QObject * parent)332 SearchBlackListDelegate::SearchBlackListDelegate(QObject *parent):
333 QStyledItemDelegate(parent)
334 {
335 }
336
~SearchBlackListDelegate()337 SearchBlackListDelegate::~SearchBlackListDelegate(){
338 }
339
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex & index) const340 QWidget *SearchBlackListDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const{
341 if (index.column() == 1){
342 QComboBox *edit = new QComboBox(parent);
343
344 edit->addItem(tr("Filename"));
345 edit->addItem(tr("TTH"));
346
347 return edit;
348 }
349 else{
350 SearchBlackListItem *item = reinterpret_cast<SearchBlackListItem*>(index.internalPointer());
351 QLineEdit *edit = new QLineEdit(parent);
352 edit->setText(item->title);
353
354 return edit;
355 }
356 }
357
updateEditorGeometry(QWidget * editor,const QStyleOptionViewItem & option,const QModelIndex & index) const358 void SearchBlackListDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const{
359 editor->setGeometry(option.rect);
360 }
361
setEditorData(QWidget * editor,const QModelIndex & index) const362 void SearchBlackListDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const{
363 SearchBlackListItem *item = reinterpret_cast<SearchBlackListItem*>(index.internalPointer());
364
365 if (!item)
366 return;
367
368 if (index.column() == 1){
369 QComboBox *edit = qobject_cast<QComboBox*>(editor);
370
371 if (!edit)
372 return;
373
374 edit->setCurrentIndex(item->argument);
375 }
376 else{
377 QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
378
379 if (!edit)
380 return;
381
382 edit->setText(item->title);
383 }
384 }
385
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const386 void SearchBlackListDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const{
387 SearchBlackListModel *m = qobject_cast<SearchBlackListModel* >(model);
388 SearchBlackListItem *item = reinterpret_cast<SearchBlackListItem* >(index.internalPointer());
389
390 if (!m)
391 return;
392
393 if (index.column() == 1){
394 QComboBox *edit = qobject_cast<QComboBox*>(editor);
395
396 if (!edit || !item)
397 return;
398
399 item->argument = edit->currentIndex();
400 }
401 else{
402 QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
403
404 if (!edit || !item)
405 return;
406
407 item->title = edit->text();
408 }
409 }
410