1 /* filter_dialog.cpp
2 *
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include <config.h>
11
12 #include <errno.h>
13
14 #include <glib.h>
15
16 #include <ui/filter_files.h>
17
18 #include <wsutil/filesystem.h>
19
20 #include "filter_dialog.h"
21 #include <ui_filter_dialog.h>
22
23 #include <QMessageBox>
24 #include <QThread>
25 #include <QUrl>
26 #include <QSortFilterProxyModel>
27
28 #include <ui/qt/utils/qt_ui_utils.h>
29 #include <ui/qt/widgets/capture_filter_edit.h>
30 #include <ui/qt/widgets/display_filter_edit.h>
31 #include "wireshark_application.h"
32
33 FilterDialog::FilterDialog(QWidget *parent, FilterType filter_type, QString new_filter_) :
34 GeometryStateDialog(parent),
35 ui(new Ui::FilterDialog),
36 filter_type_(filter_type),
37 filter_tree_delegate_(new FilterTreeDelegate(this, filter_type))
38 {
39 ui->setupUi(this);
40
41 if (parent) loadGeometry(parent->width() * 2 / 3, parent->height() * 2 / 3);
42 setWindowIcon(wsApp->normalIcon());
43
44 ui->newToolButton->setStockIcon("list-add");
45 ui->deleteToolButton->setStockIcon("list-remove");
46 ui->copyToolButton->setStockIcon("list-copy");
47
48 #ifdef Q_OS_MAC
49 ui->newToolButton->setAttribute(Qt::WA_MacSmallSize, true);
50 ui->deleteToolButton->setAttribute(Qt::WA_MacSmallSize, true);
51 ui->copyToolButton->setAttribute(Qt::WA_MacSmallSize, true);
52 ui->pathLabel->setAttribute(Qt::WA_MacSmallSize, true);
53 #endif
54
55 #if 0
56 ui->filterTreeWidget->setDragEnabled(true);
57 ui->filterTreeWidget->viewport()->setAcceptDrops(true);
58 ui->filterTreeWidget->setDropIndicatorShown(true);
59 ui->filterTreeWidget->setDragDropMode(QAbstractItemView::InternalMove);
60 #endif
61 ui->filterTreeView->setDragEnabled(true);
62 ui->filterTreeView->setAcceptDrops(true);
63 ui->filterTreeView->setDropIndicatorShown(true);
64
65 const gchar * filename = NULL;
66 QString newFilterText;
67 if (filter_type == CaptureFilter) {
68 setWindowTitle(wsApp->windowTitleString(tr("Capture Filters")));
69 filename = CFILTER_FILE_NAME;
70 newFilterText = tr("New capture filter");
71 model_ = new FilterListModel(FilterListModel::Capture, this);
72 } else {
73 setWindowTitle(wsApp->windowTitleString(tr("Display Filters")));
74 filename = DFILTER_FILE_NAME;
75 newFilterText = tr("New display filter");
76 model_ = new FilterListModel(FilterListModel::Display, this);
77 }
78
79 if (new_filter_.length() > 0)
80 model_->addFilter(newFilterText, new_filter_);
is_active()81
82 ui->filterTreeView->setModel(model_);
83
84 ui->filterTreeView->setItemDelegate(new FilterTreeDelegate(this, filter_type));
85
86 ui->filterTreeView->resizeColumnToContents(FilterListModel::ColumnName);
87
88 connect(ui->filterTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FilterDialog::selectionChanged);
89
90 QString abs_path = gchar_free_to_qstring(get_persconffile_path(filename, TRUE));
91 if (file_exists(abs_path.toUtf8().constData())) {
92 ui->pathLabel->setText(abs_path);
93 ui->pathLabel->setUrl(QUrl::fromLocalFile(abs_path).toString());
94 ui->pathLabel->setToolTip(tr("Open ") + filename);
95 ui->pathLabel->setEnabled(true);
96 }
97 }
98
99 FilterDialog::~FilterDialog()
100 {
101 delete ui;
102 }
103
104 void FilterDialog::addFilter(QString name, QString filter, bool start_editing)
105 {
106 if (model_)
107 {
108 QModelIndex idx = model_->addFilter(name, filter);
109 if (start_editing)
110 ui->filterTreeView->edit(idx);
111 }
112 }
113
114 void FilterDialog::updateWidgets()
115 {
116 if (! ui->filterTreeView->selectionModel())
117 return;
get_closest_nodes(const HashString & id)118
119 int num_selected = ui->filterTreeView->selectionModel()->selectedRows().count();
120
121 ui->copyToolButton->setEnabled(num_selected == 1);
122 ui->deleteToolButton->setEnabled(num_selected > 0);
123 }
124
125 void FilterDialog::selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
126 {
127 updateWidgets();
reset_statistics()128 }
129
130 void FilterDialog::on_newToolButton_clicked()
131 {
132 QString name;
133 QString filter;
134
135 if (filter_type_ == CaptureFilter) {
136 //: This text is automatically filled in when a new filter is created
137 name = tr("New capture filter");
138 filter = "ip host host.example.com";
139 } else {
140 //: This text is automatically filled in when a new filter is created
141 name = tr("New display filter");
142 filter = "ip.host == host.example.com";
143 }
144
145 addFilter(name, filter, true);
146 }
147
148 void FilterDialog::on_deleteToolButton_clicked()
149 {
150 QModelIndexList selected = ui->filterTreeView->selectionModel()->selectedRows();
151 QList<int> rows;
152 foreach (QModelIndex idx, selected)
153 {
154 if (idx.isValid() && ! rows.contains(idx.row()))
155 {
156 rows << idx.row();
157 model_->removeFilter(idx);
158 }
159 }
160 }
161
162 void FilterDialog::on_copyToolButton_clicked()
163 {
164 QModelIndexList selected = ui->filterTreeView->selectionModel()->selectedRows();
165 if (selected.count() <= 0)
166 return;
167
168 int rowNr = selected.at(0).row();
169 QModelIndex row = selected.at(0).sibling(rowNr, FilterListModel::ColumnName);
170
171 addFilter(row.data().toString(), row.sibling(rowNr, FilterListModel::ColumnExpression).data().toString(), true);
172 }
173
174 void FilterDialog::on_buttonBox_accepted()
175 {
176 model_->saveList();
177
178 if (filter_type_ == CaptureFilter) {
179 wsApp->emitAppSignal(WiresharkApplication::CaptureFilterListChanged);
180 } else {
181 wsApp->emitAppSignal(WiresharkApplication::DisplayFilterListChanged);
make_token(const rak::socket_address * sa,char * buffer)182 }
183 }
184
185 void FilterDialog::on_buttonBox_helpRequested()
186 {
187 if (filter_type_ == CaptureFilter) {
188 wsApp->helpTopicAction(HELP_CAPTURE_FILTERS_DIALOG);
189 } else {
190 wsApp->helpTopicAction(HELP_DISPLAY_FILTERS_DIALOG);
191 }
192 }
193
194 //
195 // FilterTreeDelegate
196 // Delegate for editing capture and display filters.
197 //
198
199 FilterTreeDelegate::FilterTreeDelegate(QObject *parent, FilterDialog::FilterType filter_type) :
200 QStyledItemDelegate(parent),
201 filter_type_(filter_type)
202 {}
203
204 QWidget *FilterTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
205 {
206 QWidget * w = Q_NULLPTR;
207 if (index.column() != FilterListModel::ColumnExpression) {
208 w = QStyledItemDelegate::createEditor(parent, option, index);
209 }
210 else
211 {
212 if (filter_type_ == FilterDialog::CaptureFilter) {
213 w = new CaptureFilterEdit(parent, true);
214 } else {
215 w = new DisplayFilterEdit(parent, DisplayFilterToEnter);
216 }
217 }
218
219 if (qobject_cast<QLineEdit *>(w) && index.column() == FilterListModel::ColumnName)
220 qobject_cast<QLineEdit *>(w)->setValidator(new FilterValidator());
221
222 return w;
223 }
224
225 void FilterTreeDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
226 {
227 if (! editor || ! index.isValid())
228 return;
229
230 QStyledItemDelegate::setEditorData(editor, index);
231
232 if (qobject_cast<QLineEdit *>(editor))
233 qobject_cast<QLineEdit *>(editor)->setText(index.data().toString());
234 }
235
236 QValidator::State FilterValidator::validate(QString & input, int & /*pos*/) const
237 {
238 /* Making this a list to be able to easily add additional values in the future */
239 QStringList invalidKeys = QStringList() << "\"";
240
241 if (input.length() <= 0)
242 return QValidator::Intermediate;
243
244 foreach (QString key, invalidKeys)
245 if (input.indexOf(key) >= 0)
246 return QValidator::Invalid;
247
248 return QValidator::Acceptable;
249 }
250