drsuapi_SupportedExtensionsExt wild guess to match 0x80a and DsGetNCChangesReq11...
[wireshark-sm.git] / ui / qt / filter_dialog.cpp
blob1173d4054f53522fa1a1c4e3ced6eac76d0fde5c
1 /* filter_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include <config.h>
12 #include <wsutil/filter_files.h>
13 #include <wsutil/filesystem.h>
15 #include "filter_dialog.h"
16 #include <ui_filter_dialog.h>
18 #include <QMessageBox>
19 #include <QThread>
20 #include <QUrl>
21 #include <QSortFilterProxyModel>
23 #include <ui/qt/utils/qt_ui_utils.h>
24 #include <ui/qt/widgets/capture_filter_edit.h>
25 #include <ui/qt/widgets/display_filter_edit.h>
26 #include "main_application.h"
28 FilterDialog::FilterDialog(QWidget *parent, FilterType filter_type, QString new_filter_) :
29 GeometryStateDialog(parent),
30 ui(new Ui::FilterDialog),
31 filter_type_(filter_type),
32 filter_tree_delegate_(new FilterTreeDelegate(this, filter_type))
34 ui->setupUi(this);
36 if (parent) loadGeometry(parent->width() * 2 / 3, parent->height() * 2 / 3);
37 setWindowIcon(mainApp->normalIcon());
39 ui->newToolButton->setStockIcon("list-add");
40 ui->deleteToolButton->setStockIcon("list-remove");
41 ui->copyToolButton->setStockIcon("list-copy");
43 #ifdef Q_OS_MAC
44 ui->newToolButton->setAttribute(Qt::WA_MacSmallSize, true);
45 ui->deleteToolButton->setAttribute(Qt::WA_MacSmallSize, true);
46 ui->copyToolButton->setAttribute(Qt::WA_MacSmallSize, true);
47 ui->pathLabel->setAttribute(Qt::WA_MacSmallSize, true);
48 #endif
50 #if 0
51 ui->filterTreeWidget->setDragEnabled(true);
52 ui->filterTreeWidget->viewport()->setAcceptDrops(true);
53 ui->filterTreeWidget->setDropIndicatorShown(true);
54 ui->filterTreeWidget->setDragDropMode(QAbstractItemView::InternalMove);
55 #endif
56 ui->filterTreeView->setDragEnabled(true);
57 ui->filterTreeView->setAcceptDrops(true);
58 ui->filterTreeView->setDropIndicatorShown(true);
60 const char * filename = NULL;
61 QString newFilterText;
62 switch (filter_type) {
63 case CaptureFilter:
64 setWindowTitle(mainApp->windowTitleString(tr("Capture Filters")));
65 filename = CFILTER_FILE_NAME;
66 newFilterText = tr("New capture filter");
67 model_ = new FilterListModel(FilterListModel::Capture, this);
68 break;
69 case DisplayFilter:
70 setWindowTitle(mainApp->windowTitleString(tr("Display Filters")));
71 filename = DFILTER_FILE_NAME;
72 newFilterText = tr("New display filter");
73 model_ = new FilterListModel(FilterListModel::Display, this);
74 break;
75 case DisplayMacro:
76 setWindowTitle(mainApp->windowTitleString(tr("Display Filter Macros")));
77 filename = DMACROS_FILE_NAME;
78 newFilterText = tr("New macro");
79 model_ = new FilterListModel(FilterListModel::DisplayMacro, this);
80 break;
81 default:
82 ws_assert_not_reached();
85 ui->filterTreeView->setModel(model_);
87 ui->filterTreeView->setItemDelegate(new FilterTreeDelegate(this, filter_type));
89 if (new_filter_.length() > 0)
90 addFilter(newFilterText, new_filter_, true);
92 ui->filterTreeView->resizeColumnToContents(FilterListModel::ColumnName);
94 connect(ui->filterTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FilterDialog::selectionChanged);
96 QString abs_path = gchar_free_to_qstring(get_persconffile_path(filename, true));
97 if (file_exists(abs_path.toUtf8().constData())) {
98 ui->pathLabel->setText(abs_path);
99 ui->pathLabel->setUrl(QUrl::fromLocalFile(abs_path).toString());
100 ui->pathLabel->setToolTip(tr("Open ") + filename);
101 ui->pathLabel->setEnabled(true);
105 FilterDialog::~FilterDialog()
107 delete ui;
110 void FilterDialog::addFilter(QString name, QString filter, bool start_editing)
112 if (model_)
114 QModelIndex idx = model_->addFilter(name, filter);
115 ui->filterTreeView->scrollTo(idx);
116 if (start_editing)
117 ui->filterTreeView->edit(idx);
118 else
119 ui->filterTreeView->selectionModel()->select(idx,QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Rows);
123 void FilterDialog::updateWidgets()
125 if (! ui->filterTreeView->selectionModel())
126 return;
128 qsizetype num_selected = ui->filterTreeView->selectionModel()->selectedRows().count();
130 ui->copyToolButton->setEnabled(num_selected == 1);
131 ui->deleteToolButton->setEnabled(num_selected > 0);
134 void FilterDialog::selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
136 updateWidgets();
139 void FilterDialog::on_newToolButton_clicked()
141 QString name;
142 QString filter;
144 switch (filter_type_) {
145 case CaptureFilter:
146 //: This text is automatically filled in when a new filter is created
147 name = tr("New capture filter");
148 filter = "ip host host.example.com";
149 break;
150 case DisplayFilter:
151 //: This text is automatically filled in when a new filter is created
152 name = tr("New display filter");
153 filter = "ip.host == host.example.com";
154 break;
155 case DisplayMacro:
156 //: This text is automatically filled in when a new filter is created
157 name = "eq_example_com";
158 filter = "$1 == host.example.com";
159 break;
160 default:
161 ws_assert_not_reached();
164 addFilter(name, filter, true);
167 void FilterDialog::on_deleteToolButton_clicked()
169 QModelIndexList selected = ui->filterTreeView->selectionModel()->selectedRows();
170 QList<int> rows;
171 foreach (QModelIndex idx, selected)
173 if (idx.isValid() && ! rows.contains(idx.row()))
175 rows << idx.row();
176 model_->removeFilter(idx);
181 void FilterDialog::on_copyToolButton_clicked()
183 QModelIndexList selected = ui->filterTreeView->selectionModel()->selectedRows();
184 if (selected.count() <= 0)
185 return;
187 int rowNr = selected.at(0).row();
188 QModelIndex row = selected.at(0).sibling(rowNr, FilterListModel::ColumnName);
190 addFilter(row.data().toString(), row.sibling(rowNr, FilterListModel::ColumnExpression).data().toString(), true);
193 void FilterDialog::on_buttonBox_accepted()
195 model_->saveList();
197 switch (filter_type_) {
198 case CaptureFilter:
199 mainApp->emitAppSignal(MainApplication::CaptureFilterListChanged);
200 break;
201 case DisplayFilter:
202 mainApp->emitAppSignal(MainApplication::DisplayFilterListChanged);
203 break;
204 case DisplayMacro:
205 mainApp->reloadDisplayFilterMacros();
206 // The function above emits MainApplication::FieldsChanged, which
207 // takes care of invalidating the current display filter text if
208 // it no longer compiles.
209 // XXX - What if the current display filter means something
210 // different now? Should we force a refilter (not redissection,
211 // the dissection shouldn't have changed) with the current display
212 // filter, or wait for the user to refilter?
213 // The UAT based display macro system did not refilter.
214 break;
215 default:
216 ws_assert_not_reached();
220 void FilterDialog::on_buttonBox_helpRequested()
222 switch (filter_type_) {
223 case CaptureFilter:
224 mainApp->helpTopicAction(HELP_CAPTURE_FILTERS_DIALOG);
225 break;
226 case DisplayFilter:
227 mainApp->helpTopicAction(HELP_DISPLAY_FILTERS_DIALOG);
228 break;
229 case DisplayMacro:
230 mainApp->helpTopicAction(HELP_DISPLAY_MACRO_DIALOG);
231 break;
232 default:
233 ws_assert_not_reached();
238 // FilterTreeDelegate
239 // Delegate for editing capture and display filters.
242 FilterTreeDelegate::FilterTreeDelegate(QObject *parent, FilterDialog::FilterType filter_type) :
243 QStyledItemDelegate(parent),
244 filter_type_(filter_type)
247 QWidget *FilterTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
249 QWidget * w = Q_NULLPTR;
250 if (index.column() != FilterListModel::ColumnExpression) {
251 w = QStyledItemDelegate::createEditor(parent, option, index);
253 else if (filter_type_ == FilterDialog::CaptureFilter) {
254 w = new CaptureFilterEdit(parent, true);
256 else if (filter_type_ == FilterDialog::DisplayFilter) {
257 w = new DisplayFilterEdit(parent, DisplayFilterToEnter);
259 else {
260 w = QStyledItemDelegate::createEditor(parent, option, index);
263 if (qobject_cast<QLineEdit *>(w)) {
264 if (index.column() == FilterListModel::ColumnName) {
265 if (filter_type_ == FilterDialog::DisplayMacro) {
266 qobject_cast<QLineEdit *>(w)->setValidator(new MacroNameValidator());
268 else {
269 qobject_cast<QLineEdit *>(w)->setValidator(new FilterValidator());
274 return w;
277 void FilterTreeDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
279 if (! editor || ! index.isValid())
280 return;
282 QStyledItemDelegate::setEditorData(editor, index);
284 if (qobject_cast<QLineEdit *>(editor))
285 qobject_cast<QLineEdit *>(editor)->setText(index.data().toString());
288 QValidator::State FilterValidator::validate(QString & input, int & /*pos*/) const
290 /* Making this a list to be able to easily add additional values in the future */
291 QStringList invalidKeys = QStringList() << "\"";
293 if (input.length() <= 0)
294 return QValidator::Intermediate;
296 foreach (QString key, invalidKeys)
297 if (input.indexOf(key) >= 0)
298 return QValidator::Invalid;
300 return QValidator::Acceptable;
303 QValidator::State MacroNameValidator::validate(QString &input, int & /*pos*/) const
305 if (input.length() <= 0)
306 return QValidator::Intermediate;
308 for (QChar ch: input) {
309 if (!ch.isLetterOrNumber() && ch != '_') {
310 return QValidator::Invalid;
314 return QValidator::Acceptable;