aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2015-06-01 16:29:17 -0700
committerGerald Combs <gerald@wireshark.org>2015-06-03 02:27:00 +0000
commitec3f923e3e693a3ca469bb7073a8c9ce2c33cb7d (patch)
tree0c22e44bfe372915d7831e8fde1c74504b480075
parent32177ceec8aedc9130f95e4ead34d5b5155ea17d (diff)
Add the Display Filter Expression dialog.
Changes from the GTK+ UI: - The display filter is built on the fly with immediate syntax feedback. - Slightly different layout. - You can search for fields. Make the plain SyntaxLineEdit a bit more plain. Bug: 11128 Change-Id: I06a48cd7b9ba7b9dc193b0199540aede4eb62fa7 Reviewed-on: https://code.wireshark.org/review/8742 Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
-rw-r--r--docbook/wsug_src/WSUG_chapter_work.asciidoc6
-rw-r--r--epan/range.c2
-rw-r--r--epan/range.h10
-rw-r--r--epan/tfs.h10
-rw-r--r--ui/gtk/dfilter_expr_dlg.c3
-rw-r--r--ui/help_url.c3
-rw-r--r--ui/help_url.h1
-rw-r--r--ui/qt/CMakeLists.txt3
-rw-r--r--ui/qt/Makefile.am2
-rw-r--r--ui/qt/Makefile.common4
-rw-r--r--ui/qt/Wireshark.pro3
-rw-r--r--ui/qt/display_filter_edit.cpp136
-rw-r--r--ui/qt/display_filter_expression_dialog.cpp427
-rw-r--r--ui/qt/display_filter_expression_dialog.h86
-rw-r--r--ui/qt/display_filter_expression_dialog.ui242
-rw-r--r--ui/qt/main_window.cpp2
-rw-r--r--ui/qt/main_window.h1
-rw-r--r--ui/qt/main_window.ui12
-rw-r--r--ui/qt/main_window_slots.cpp20
-rw-r--r--ui/qt/qt_ui_utils.cpp12
-rw-r--r--ui/qt/qt_ui_utils.h32
-rw-r--r--ui/qt/syntax_line_edit.cpp18
-rw-r--r--ui/qt/syntax_line_edit.h2
23 files changed, 946 insertions, 91 deletions
diff --git a/docbook/wsug_src/WSUG_chapter_work.asciidoc b/docbook/wsug_src/WSUG_chapter_work.asciidoc
index 96274d5b4d..ecce012c29 100644
--- a/docbook/wsug_src/WSUG_chapter_work.asciidoc
+++ b/docbook/wsug_src/WSUG_chapter_work.asciidoc
@@ -421,8 +421,8 @@ for which there are no occurrences of a field named ip.addr with the value
When you are accustomed to Wireshark's filtering system and know what labels you
wish to use in your filters it can be very quick to simply type a filter string.
However if you are new to Wireshark or are working with a slightly unfamiliar
-protocol it can be very confusing to try to figure out what to type. The Filter
-Expression dialog box helps with this.
+protocol it can be very confusing to try to figure out what to type. The
+``Filter Expression'' dialog box helps with this.
[TIP]
====
@@ -437,7 +437,7 @@ Wireshark display filter strings.
image::wsug_graphics/ws-filter-add-expression.png[]
When you first bring up the Filter Expression dialog box you are shown a tree
-list of field names, organized by protocol, and a box for selecting a relation.
+of field names, organized by protocol, and a box for selecting a relation.
_Field Name_::
Select a protocol field from the protocol field tree. Every protocol with
diff --git a/epan/range.c b/epan/range.c
index cc58292f73..07406c138e 100644
--- a/epan/range.c
+++ b/epan/range.c
@@ -323,7 +323,7 @@ range_foreach(range_t *range, void (*callback)(guint32 val))
/* This function converts a range_t to a (wmem-allocated) string. */
char *
-range_convert_range(wmem_allocator_t *scope, range_t *range)
+range_convert_range(wmem_allocator_t *scope, const range_t *range)
{
guint32 i;
gboolean prepend_comma = FALSE;
diff --git a/epan/range.h b/epan/range.h
index a7b8f5c748..f4c5549a0d 100644
--- a/epan/range.h
+++ b/epan/range.h
@@ -30,6 +30,10 @@
#include "ws_symbol_export.h"
#include <epan/wmem/wmem.h>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
/** @file
* Range strings a variant of value_strings
*/
@@ -116,7 +120,7 @@ WS_DLL_PUBLIC void range_foreach(range_t *range, void (*callback)(guint32 val));
/**
* This function converts a range_t to a (wmem_alloc()-allocated) string.
*/
-WS_DLL_PUBLIC char *range_convert_range(wmem_allocator_t *scope, range_t *range);
+WS_DLL_PUBLIC char *range_convert_range(wmem_allocator_t *scope, const range_t *range);
/**
* Create a copy of a range.
@@ -125,4 +129,8 @@ WS_DLL_PUBLIC char *range_convert_range(wmem_allocator_t *scope, range_t *range)
*/
WS_DLL_PUBLIC range_t *range_copy(range_t *src);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
#endif /* __RANGE_H__ */
diff --git a/epan/tfs.h b/epan/tfs.h
index 7ba9dea0ca..d7487f9545 100644
--- a/epan/tfs.h
+++ b/epan/tfs.h
@@ -26,6 +26,10 @@
#include "ws_symbol_export.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
/** @file
* true_false strings
*/
@@ -97,4 +101,8 @@ WS_DLL_PUBLIC const true_false_string tfs_protocol_sensative_bit_transparent;
WS_DLL_PUBLIC const true_false_string tfs_full_half;
WS_DLL_PUBLIC const true_false_string tfs_acknowledged_not_acknowledged;
-#endif
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TFS_H__ */
diff --git a/ui/gtk/dfilter_expr_dlg.c b/ui/gtk/dfilter_expr_dlg.c
index 16ca3cabc4..bf813f1a2a 100644
--- a/ui/gtk/dfilter_expr_dlg.c
+++ b/ui/gtk/dfilter_expr_dlg.c
@@ -322,7 +322,6 @@ static void
build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
const true_false_string *values)
{
- static const true_false_string true_false = { "True", "False" };
GtkTreeSelection *sel;
GtkTreeIter iter;
@@ -346,7 +345,7 @@ build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
* Build the list.
*/
if (values == NULL)
- values = &true_false;
+ values = &tfs_true_false;
add_value_list_item(value_list, values->true_string, (gpointer) values);
add_value_list_item(value_list, values->false_string, NULL);
diff --git a/ui/help_url.c b/ui/help_url.c
index 6a93cb9407..f45315002e 100644
--- a/ui/help_url.c
+++ b/ui/help_url.c
@@ -214,6 +214,9 @@ topic_action_url(topic_action_e action)
case(HELP_DISPLAY_FILTERS_DIALOG):
url = user_guide_url("ChWorkDefineFilterSection.html");
break;
+ case(HELP_FILTER_EXPRESSION_DIALOG):
+ url = user_guide_url("ChWorkFilterAddExpressionSection.html");
+ break;
case(HELP_COLORING_RULES_DIALOG):
url = user_guide_url("ChCustColorizationSection.html");
break;
diff --git a/ui/help_url.h b/ui/help_url.h
index 033ef8ff8c..bbf82821da 100644
--- a/ui/help_url.h
+++ b/ui/help_url.h
@@ -68,6 +68,7 @@ typedef enum {
HELP_CAPTURE_OPTIONS_DIALOG,
HELP_CAPTURE_FILTERS_DIALOG,
HELP_DISPLAY_FILTERS_DIALOG,
+ HELP_FILTER_EXPRESSION_DIALOG,
HELP_COLORING_RULES_DIALOG,
HELP_CONFIG_PROFILES_DIALOG,
HELP_MANUAL_ADDR_RESOLVE_DIALOG,
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 821aaf1837..8ad40bf071 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -45,6 +45,7 @@ set(WIRESHARK_QT_HEADERS
decode_as_dialog.h
display_filter_combo.h
display_filter_edit.h
+ display_filter_expression_dialog.h
elided_label.h
endpoint_dialog.h
expert_info_dialog.h
@@ -157,6 +158,7 @@ set(WIRESHARK_QT_SRC
decode_as_dialog.cpp
display_filter_combo.cpp
display_filter_edit.cpp
+ display_filter_expression_dialog.cpp
elided_label.cpp
expert_info_dialog.cpp
export_dissection_dialog.cpp
@@ -264,6 +266,7 @@ set(WIRESHARK_QT_UI
column_editor_frame.ui
compiled_filter_output.ui
decode_as_dialog.ui
+ display_filter_expression_dialog.ui
expert_info_dialog.ui
export_object_dialog.ui
export_pdu_dialog.ui
diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am
index d29a8235c3..b5362ad66c 100644
--- a/ui/qt/Makefile.am
+++ b/ui/qt/Makefile.am
@@ -140,6 +140,8 @@ compiled_filter_output.cpp compiled_filter_output.h: ui_compiled_filter_output.h
decode_as_dialog.cpp decode_as_dialog.h: ui_decode_as_dialog.h
+display_filter_expression_dialog.cpp display_filter_expression_dialog.h: ui_display_filter_expression_dialog.h
+
expert_info_dialog.cpp expert_info_dialog.h: ui_expert_info_dialog.h
export_object_dialog.cpp export_object_dialog.h: ui_export_object_dialog.h
diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common
index b9a2705c73..fe136da9c7 100644
--- a/ui/qt/Makefile.common
+++ b/ui/qt/Makefile.common
@@ -39,6 +39,7 @@ NODIST_GENERATED_HEADER_FILES = \
ui_column_editor_frame.h \
ui_compiled_filter_output.h \
ui_decode_as_dialog.h \
+ ui_display_filter_expression_dialog.h \
ui_expert_info_dialog.h \
ui_export_object_dialog.h \
ui_export_pdu_dialog.h \
@@ -143,6 +144,7 @@ MOC_HDRS = \
decode_as_dialog.h \
display_filter_combo.h \
display_filter_edit.h \
+ display_filter_expression_dialog.h \
elided_label.h \
endpoint_dialog.h \
expert_info_dialog.h \
@@ -228,6 +230,7 @@ UI_FILES = \
column_editor_frame.ui \
compiled_filter_output.ui \
decode_as_dialog.ui \
+ display_filter_expression_dialog.ui \
expert_info_dialog.ui \
export_object_dialog.ui \
export_pdu_dialog.ui \
@@ -348,6 +351,7 @@ WIRESHARK_QT_SRC = \
decode_as_dialog.cpp \
display_filter_combo.cpp \
display_filter_edit.cpp \
+ display_filter_expression_dialog.cpp \
elided_label.cpp \
endpoint_dialog.cpp \
expert_info_dialog.cpp \
diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro
index 6cfe6088db..d781395a31 100644
--- a/ui/qt/Wireshark.pro
+++ b/ui/qt/Wireshark.pro
@@ -215,6 +215,7 @@ FORMS += \
column_editor_frame.ui \
compiled_filter_output.ui \
decode_as_dialog.ui \
+ display_filter_expression_dialog.ui \
expert_info_dialog.ui \
export_object_dialog.ui \
export_pdu_dialog.ui \
@@ -276,6 +277,7 @@ HEADERS += $$HEADERS_WS_C \
compiled_filter_output.h \
conversation_dialog.h \
decode_as_dialog.h \
+ display_filter_expression_dialog.h \
elided_label.h \
endpoint_dialog.h \
expert_info_dialog.h \
@@ -628,6 +630,7 @@ SOURCES += \
decode_as_dialog.cpp \
display_filter_combo.cpp \
display_filter_edit.cpp \
+ display_filter_expression_dialog.cpp \
elided_label.cpp \
endpoint_dialog.cpp \
expert_info_dialog.cpp \
diff --git a/ui/qt/display_filter_edit.cpp b/ui/qt/display_filter_edit.cpp
index 09fc1fb8d3..b0f266dc9c 100644
--- a/ui/qt/display_filter_edit.cpp
+++ b/ui/qt/display_filter_edit.cpp
@@ -99,6 +99,8 @@ static const QString fld_abbrev_chars_ = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
DisplayFilterEdit::DisplayFilterEdit(QWidget *parent, bool plain) :
SyntaxLineEdit(parent),
plain_(plain),
+ bookmark_button_(NULL),
+ clear_button_(NULL),
apply_button_(NULL)
{
setAccessibleName(tr("Display filter entry"));
@@ -124,61 +126,64 @@ DisplayFilterEdit::DisplayFilterEdit(QWidget *parent, bool plain) :
// Apply (right arrow) + Cancel (x) + Reload (arrowed circle)
// Combo drop-down
- bookmark_button_ = new QToolButton(this);
- bookmark_button_->setEnabled(false);
- bookmark_button_->setCursor(Qt::ArrowCursor);
- bookmark_button_->setStyleSheet(QString(
- "QToolButton { /* all types of tool button */"
- " border 0 0 0 0;"
+ if (!plain_) {
+ bookmark_button_ = new QToolButton(this);
+ bookmark_button_->setEnabled(false);
+ bookmark_button_->setCursor(Qt::ArrowCursor);
+ bookmark_button_->setStyleSheet(QString(
+ "QToolButton { /* all types of tool button */"
+ " border 0 0 0 0;"
#ifdef Q_OS_MAC
- " border-right: %1px solid gray;"
+ " border-right: %1px solid gray;"
#else
- " border-right: %1px solid palette(shadow);"
+ " border-right: %1px solid palette(shadow);"
#endif
- " border-top-left-radius: 3px;"
- " border-bottom-left-radius: 3px;"
- " padding-left: 1px;"
- " image: url(:/dfilter/dfilter_bookmark_normal.png) center;"
- "}"
-
- "QToolButton:hover {"
- " image: url(:/dfilter/dfilter_bookmark_hover.png) center;"
- "}"
- "QToolButton:pressed {"
- " image: url(:/dfilter/dfilter_bookmark_pressed.png) center;"
- "}"
- "QToolButton:disabled {"
- " image: url(:/dfilter/dfilter_bookmark_disabled.png) center;"
- "}"
-
+ " border-top-left-radius: 3px;"
+ " border-bottom-left-radius: 3px;"
+ " padding-left: 1px;"
+ " image: url(:/dfilter/dfilter_bookmark_normal.png) center;"
+ "}"
- ).arg(plain_ ? 0 : 1)
- );
+ "QToolButton:hover {"
+ " image: url(:/dfilter/dfilter_bookmark_hover.png) center;"
+ "}"
+ "QToolButton:pressed {"
+ " image: url(:/dfilter/dfilter_bookmark_pressed.png) center;"
+ "}"
+ "QToolButton:disabled {"
+ " image: url(:/dfilter/dfilter_bookmark_disabled.png) center;"
+ "}"
+ ).arg(plain_ ? 0 : 1)
+ );
#ifndef QT_NO_TOOLTIP
- bookmark_button_->setToolTip(tr("Bookmark this filter string"));
+ bookmark_button_->setToolTip(tr("Bookmark this filter string"));
#endif // QT_NO_TOOLTIP
- connect(bookmark_button_, SIGNAL(clicked()), this, SLOT(bookmarkClicked()));
-
- clear_button_ = new QToolButton(this);
- clear_button_->setCursor(Qt::ArrowCursor);
- clear_button_->setStyleSheet(
- "QToolButton {"
- " image: url(:/dfilter/dfilter_erase_normal.png) center;"
- " border: none;"
- " width: 16px;"
- "}"
- "QToolButton:hover {"
- " image: url(:/dfilter/dfilter_erase_active.png) center;"
- "}"
- "QToolButton:pressed {"
- " image: url(:/dfilter/dfilter_erase_selected.png) center;"
- "}"
- );
+ connect(bookmark_button_, SIGNAL(clicked()), this, SLOT(bookmarkClicked()));
+ }
+
+ if (!plain_) {
+ clear_button_ = new QToolButton(this);
+ clear_button_->setCursor(Qt::ArrowCursor);
+ clear_button_->setStyleSheet(
+ "QToolButton {"
+ " image: url(:/dfilter/dfilter_erase_normal.png) center;"
+ " border: none;"
+ " width: 16px;"
+ "}"
+ "QToolButton:hover {"
+ " image: url(:/dfilter/dfilter_erase_active.png) center;"
+ "}"
+ "QToolButton:pressed {"
+ " image: url(:/dfilter/dfilter_erase_selected.png) center;"
+ "}"
+ );
#ifndef QT_NO_TOOLTIP
- clear_button_->setToolTip(tr("Clear the filter string and update the display"));
+ clear_button_->setToolTip(tr("Clear the filter string and update the display"));
#endif // QT_NO_TOOLTIP
- clear_button_->hide();
- connect(clear_button_, SIGNAL(clicked()), this, SLOT(clearFilter()));
+ clear_button_->hide();
+ connect(clear_button_, SIGNAL(clicked()), this, SLOT(clearFilter()));
+ }
+
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(checkFilter(const QString&)));
if (!plain_) {
@@ -212,13 +217,17 @@ DisplayFilterEdit::DisplayFilterEdit(QWidget *parent, bool plain) :
}
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
- QSize bksz = bookmark_button_->sizeHint();
- QSize cbsz = clear_button_->sizeHint();
+ QSize bksz;
+ if (bookmark_button_) {
+ bksz = bookmark_button_->sizeHint();
+ }
+ QSize cbsz;
+ if (clear_button_) {
+ cbsz = clear_button_->sizeHint();
+ }
QSize apsz;
if (apply_button_) {
apsz = apply_button_->sizeHint();
- } else {
- apsz.setHeight(0); apsz.setWidth(0);
}
setStyleSheet(QString(
"DisplayFilterEdit {"
@@ -263,7 +272,10 @@ void DisplayFilterEdit::paintEvent(QPaintEvent *evt) {
void DisplayFilterEdit::resizeEvent(QResizeEvent *)
{
- QSize cbsz = clear_button_->sizeHint();
+ QSize cbsz;
+ if (clear_button_) {
+ cbsz = clear_button_->sizeHint();
+ }
QSize apsz;
if (apply_button_) {
apsz = apply_button_->sizeHint();
@@ -271,15 +283,19 @@ void DisplayFilterEdit::resizeEvent(QResizeEvent *)
apsz.setHeight(0); apsz.setWidth(0);
}
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
- clear_button_->move(contentsRect().right() - frameWidth - cbsz.width() - apsz.width(),
- contentsRect().top());
- clear_button_->setMaximumHeight(contentsRect().height());
+ if (clear_button_) {
+ clear_button_->move(contentsRect().right() - frameWidth - cbsz.width() - apsz.width(),
+ contentsRect().top());
+ clear_button_->setMaximumHeight(contentsRect().height());
+ }
if (apply_button_) {
apply_button_->move(contentsRect().right() - frameWidth - apsz.width(),
contentsRect().top());
apply_button_->setMaximumHeight(contentsRect().height());
}
- bookmark_button_->setMaximumHeight(contentsRect().height());
+ if (bookmark_button_) {
+ bookmark_button_->setMaximumHeight(contentsRect().height());
+ }
}
void DisplayFilterEdit::focusOutEvent(QFocusEvent *event)
@@ -291,7 +307,9 @@ void DisplayFilterEdit::focusOutEvent(QFocusEvent *event)
void DisplayFilterEdit::checkFilter(const QString& text)
{
- clear_button_->setVisible(!text.isEmpty());
+ if (clear_button_) {
+ clear_button_->setVisible(!text.isEmpty());
+ }
popFilterSyntaxStatus();
checkDisplayFilter(text);
@@ -319,7 +337,9 @@ void DisplayFilterEdit::checkFilter(const QString& text)
break;
}
- bookmark_button_->setEnabled(syntaxState() == Valid || syntaxState() == Deprecated);
+ if (bookmark_button_) {
+ bookmark_button_->setEnabled(syntaxState() == Valid || syntaxState() == Deprecated);
+ }
if (apply_button_) {
apply_button_->setEnabled(SyntaxState() != Invalid);
}
diff --git a/ui/qt/display_filter_expression_dialog.cpp b/ui/qt/display_filter_expression_dialog.cpp
new file mode 100644
index 0000000000..45ed9d6a50
--- /dev/null
+++ b/ui/qt/display_filter_expression_dialog.cpp
@@ -0,0 +1,427 @@
+/* display_filter_expression_dialog.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "display_filter_expression_dialog.h"
+#include "ui_display_filter_expression_dialog.h"
+
+#include <epan/proto.h>
+#include <epan/range.h>
+#include <epan/tfs.h>
+#include <epan/value_string.h>
+
+#include <ui/utf8_entities.h>
+
+#include "qt_ui_utils.h"
+#include "wireshark_application.h"
+
+#include <QPushButton>
+#include <QDialogButtonBox>
+#include <QListWidgetItem>
+#include <QTreeWidgetItem>
+
+// To do:
+// - Speed up initialization.
+// - Speed up search.
+
+enum {
+ proto_type_ = 1000,
+ field_type_
+};
+
+enum {
+ present_op_ = 1000,
+ eq_op_,
+ ne_op_,
+ gt_op_,
+ lt_op_,
+ ge_op_,
+ le_op_,
+ contains_op_,
+ matches_op_
+};
+
+Q_DECLARE_METATYPE(header_field_info *)
+
+DisplayFilterExpressionDialog::DisplayFilterExpressionDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::DisplayFilterExpressionDialog),
+ ftype_(FT_NONE),
+ field_(NULL)
+{
+ ui->setupUi(this);
+ setWindowTitle(wsApp->windowTitleString(tr("Display Filter Expression")));
+
+ // XXX Use recent settings instead
+ resize(parent->width() * 2 / 3, parent->height());
+
+ ui->fieldTreeWidget->setToolTip(ui->fieldLabel->toolTip());
+ ui->searchLineEdit->setToolTip(ui->searchLabel->toolTip());
+ ui->relationListWidget->setToolTip(ui->relationLabel->toolTip());
+ ui->valueLineEdit->setToolTip(ui->valueLabel->toolTip());
+ ui->enumListWidget->setToolTip(ui->enumLabel->toolTip());
+ ui->rangeLineEdit->setToolTip(ui->rangeLabel->toolTip());
+
+ // Field tree
+ ui->fieldTreeWidget->setUpdatesEnabled(false);
+ void *proto_cookie;
+ for (int proto_id = proto_get_first_protocol(&proto_cookie); proto_id != -1; proto_id = proto_get_next_protocol(&proto_cookie)) {
+ protocol_t *protocol = find_protocol_by_id(proto_id);
+ if (!proto_is_protocol_enabled(protocol)) continue;
+
+ QTreeWidgetItem *proto_ti = new QTreeWidgetItem(proto_type_);
+ QString label = QString("%1 " UTF8_MIDDLE_DOT " %3")
+ .arg(proto_get_protocol_short_name(protocol))
+ .arg(proto_get_protocol_long_name(protocol));
+ proto_ti->setText(0, label);
+ proto_ti->setData(0, Qt::UserRole, qVariantFromValue(proto_id));
+
+ QList<QTreeWidgetItem *> fti_list;
+ void *field_cookie;
+ for (header_field_info *hfinfo = proto_get_first_protocol_field(proto_id, &field_cookie); hfinfo; hfinfo = proto_get_next_protocol_field(proto_id, &field_cookie)) {
+ if (hfinfo->same_name_prev_id != -1) continue; // Ignore duplicate names.
+
+ QTreeWidgetItem *field_ti = new QTreeWidgetItem(field_type_);
+ label = QString("%1 " UTF8_MIDDLE_DOT " %3").arg(hfinfo->abbrev).arg(hfinfo->name);
+ field_ti->setText(0, label);
+ field_ti->setData(0, Qt::UserRole, qVariantFromValue(hfinfo));
+ fti_list << field_ti;
+ }
+ proto_ti->addChildren(fti_list);
+ ui->fieldTreeWidget->addTopLevelItem(proto_ti);
+ }
+ ui->fieldTreeWidget->sortByColumn(0, Qt::AscendingOrder);
+ ui->fieldTreeWidget->setUpdatesEnabled(true);
+
+ // Relation list
+ new QListWidgetItem("is present", ui->relationListWidget, present_op_);
+ new QListWidgetItem("==", ui->relationListWidget, eq_op_);
+ new QListWidgetItem("!=", ui->relationListWidget, ne_op_);
+ new QListWidgetItem(">", ui->relationListWidget, gt_op_);
+ new QListWidgetItem("<", ui->relationListWidget, lt_op_);
+ new QListWidgetItem(">=", ui->relationListWidget, ge_op_);
+ new QListWidgetItem("<=", ui->relationListWidget, le_op_);
+ new QListWidgetItem("contains", ui->relationListWidget, contains_op_);
+ new QListWidgetItem("matches", ui->relationListWidget, matches_op_);
+
+ value_label_pfx_ = ui->valueLabel->text();
+
+ connect(ui->valueLineEdit, SIGNAL(textEdited(QString)), this, SLOT(updateWidgets()));
+ connect(ui->rangeLineEdit, SIGNAL(textEdited(QString)), this, SLOT(updateWidgets()));
+
+ // Trigger updateWidgets
+ if (ui->fieldTreeWidget->topLevelItemCount() > 0) {
+ ui->fieldTreeWidget->topLevelItem(0)->setSelected(true);
+ }
+}
+
+DisplayFilterExpressionDialog::~DisplayFilterExpressionDialog()
+{
+ delete ui;
+}
+
+void DisplayFilterExpressionDialog::updateWidgets()
+{
+ bool rel_enable = field_ != NULL;
+
+ ui->relationLabel->setEnabled(rel_enable);
+ ui->relationListWidget->setEnabled(rel_enable);
+ ui->hintLabel->clear();
+
+ bool value_enable = false;
+ bool enum_enable = false;
+ bool range_enable = false;
+
+ QString filter;
+ if (field_ && rel_enable) {
+ filter = field_;
+ QListWidgetItem *rli = ui->relationListWidget->currentItem();
+ if (rli && rli->type() != present_op_) {
+ value_enable = true;
+ if (ftype_can_slice(ftype_)) {
+ range_enable = true;
+ }
+ enum_enable = ui->enumListWidget->count() > 0;
+ filter.append(QString(" %1").arg(rli->text()));
+ }
+ if (value_enable && !ui->valueLineEdit->text().isEmpty()) {
+ if (ftype_ == FT_STRING) {
+ filter.append(QString(" \"%1\"").arg(ui->valueLineEdit->text()));
+ } else {
+ filter.append(QString(" %1").arg(ui->valueLineEdit->text()));
+ }
+ }
+ }
+
+ ui->valueLabel->setEnabled(value_enable);
+ ui->valueLineEdit->setEnabled(value_enable);
+
+ ui->enumLabel->setEnabled(enum_enable);
+ ui->enumListWidget->setEnabled(enum_enable);
+
+ ui->rangeLabel->setEnabled(range_enable);
+ ui->rangeLineEdit->setEnabled(range_enable);
+
+ ui->displayFilterLineEdit->setText(filter);
+
+ QString hint = "<small><i>";
+ if (ui->fieldTreeWidget->selectedItems().count() < 1) {
+ hint.append(tr("Select a field name to get started"));
+ } else if (ui->displayFilterLineEdit->syntaxState() != SyntaxLineEdit::Valid) {
+ hint.append(ui->displayFilterLineEdit->syntaxErrorMessage());
+ } else {
+ hint.append(tr("Click OK to insert this filter"));
+ }
+ hint.append("</i></small>");
+ ui->hintLabel->setText(hint);
+
+ QPushButton *ok_bt = ui->buttonBox->button(QDialogButtonBox::Ok);
+ if (ok_bt) {
+ bool ok_enable = !ui->displayFilterLineEdit->text().isEmpty()
+ && (ui->displayFilterLineEdit->syntaxState() == SyntaxLineEdit::Valid);
+ ok_bt->setEnabled(ok_enable);
+ }
+}
+
+void DisplayFilterExpressionDialog::fillEnumBooleanValues(const true_false_string *tfs)
+{
+ if (!tfs) tfs = &tfs_true_false;
+ QListWidgetItem *eli = new QListWidgetItem(tfs->true_string, ui->enumListWidget);
+ eli->setData(Qt::UserRole, QString("1"));
+ eli = new QListWidgetItem(tfs->false_string, ui->enumListWidget);
+ eli->setData(Qt::UserRole, QString("0"));
+}
+
+void DisplayFilterExpressionDialog::fillEnumIntValues(const _value_string *vals, int base)
+{
+ if (!vals) return;
+
+ for (int i = 0; vals[i].strptr != NULL; i++) {
+ QListWidgetItem *eli = new QListWidgetItem(vals[i].strptr, ui->enumListWidget);
+ eli->setData(Qt::UserRole, QString::number(vals[i].value, base));
+ }
+}
+
+void DisplayFilterExpressionDialog::fillEnumInt64Values(const _val64_string *vals64, int base)
+{
+ if (!vals64) return;
+
+ for (int i = 0; vals64[i].strptr != NULL; i++) {
+ QListWidgetItem *eli = new QListWidgetItem(vals64[i].strptr, ui->enumListWidget);
+ eli->setData(Qt::UserRole, QString::number(vals64[i].value, base));
+ }
+}
+
+void DisplayFilterExpressionDialog::fillEnumRangeValues(const _range_string *rvals)
+{
+ if (!rvals) return;
+
+ for (int i = 0; rvals[i].strptr != NULL; i++) {
+ QString range_text = rvals[i].strptr;
+
+ // Tell the user which values are valid here. Default to value_min below.
+ if (rvals[i].value_min != rvals[i].value_max) {
+ range_t range;
+ range.nranges = 1;
+ range.ranges[0].low = rvals[i].value_min;
+ range.ranges[0].high = rvals[i].value_max;
+ range_text.append(QString(" (%1 valid)").arg(range_to_qstring(&range)));
+ }
+
+ QListWidgetItem *eli = new QListWidgetItem(range_text, ui->enumListWidget);
+ eli->setData(Qt::UserRole, QString::number(rvals[i].value_min));
+ }
+}
+
+void DisplayFilterExpressionDialog::on_fieldTreeWidget_itemSelectionChanged()
+{
+ ftype_ = FT_NONE;
+ field_ = NULL;
+ QTreeWidgetItem *cur_fti = NULL;
+
+ if (ui->fieldTreeWidget->selectedItems().count() > 0) {
+ cur_fti = ui->fieldTreeWidget->selectedItems()[0];
+ }
+ ui->valueLineEdit->clear();
+ ui->enumListWidget->clear();
+ ui->rangeLineEdit->clear();
+
+ if (cur_fti && cur_fti->type() == proto_type_) {
+ ftype_ = FT_PROTOCOL;
+ field_ = proto_get_protocol_filter_name(cur_fti->data(0, Qt::UserRole).toInt());
+ } else if (cur_fti && cur_fti->type() == field_type_) {
+ header_field_info *hfinfo = cur_fti->data(0, Qt::UserRole).value<header_field_info*>();
+ if (hfinfo) {
+ ftype_ = hfinfo->type;
+ field_ = hfinfo->abbrev;
+
+ switch(ftype_) {
+ case FT_BOOLEAN:
+ // Let the user select the "True" and "False" values.
+ fillEnumBooleanValues((const true_false_string *)hfinfo->strings);
+ break;
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ {
+ int base;
+
+ switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
+ case BASE_HEX:
+ case BASE_HEX_DEC:
+ base = 16;
+ break;
+ case BASE_OCT:
+ base = 8;
+ break;
+ default:
+ base = 10;
+ break;
+ }
+ // Let the user select from a list of value_string or range_string values.
+ if (hfinfo->strings && ! ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM)) {
+ if (hfinfo->display & BASE_RANGE_STRING) {
+ fillEnumRangeValues((const range_string *)hfinfo->strings);
+ } else if (hfinfo->display & BASE_VAL64_STRING) {
+ const val64_string *vals = (const val64_string *)hfinfo->strings;
+ fillEnumInt64Values(vals, base);
+ } else { // Plain old value_string / VALS
+ const value_string *vals = (const value_string *)hfinfo->strings;
+ if (hfinfo->display & BASE_EXT_STRING)
+ vals = VALUE_STRING_EXT_VS_P((value_string_ext *)vals);
+ fillEnumIntValues(vals, base);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ if (ui->enumListWidget->count() > 0) {
+ ui->enumListWidget->setCurrentRow(0);
+ }
+
+ bool all_show = field_ != NULL;
+ for (int i = 0; i < ui->relationListWidget->count(); i++) {
+ QListWidgetItem *li = ui->relationListWidget->item(i);
+ switch (li->type()) {
+ case eq_op_:
+ li->setHidden(!ftype_can_eq(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_eq(FT_BYTES)));
+ break;
+ case ne_op_:
+ li->setHidden(!ftype_can_ne(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_ne(FT_BYTES)));
+ break;
+ case gt_op_:
+ li->setHidden(!ftype_can_gt(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_gt(FT_BYTES)));
+ break;
+ case lt_op_:
+ li->setHidden(!ftype_can_lt(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_lt(FT_BYTES)));
+ break;
+ case ge_op_:
+ li->setHidden(!ftype_can_ge(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_ge(FT_BYTES)));
+ break;
+ case le_op_:
+ li->setHidden(!ftype_can_le(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_le(FT_BYTES)));
+ break;
+ case contains_op_:
+ li->setHidden(!ftype_can_contains(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_contains(FT_BYTES)));
+ break;
+ case matches_op_:
+ li->setHidden(!ftype_can_matches(ftype_) && !(ftype_can_slice(ftype_) && ftype_can_matches(FT_BYTES)));
+ break;
+ default:
+ li->setHidden(!all_show);
+ break;
+ }
+ }
+ if (all_show) {
+ // Select "==" if it's present and we have a value, "is present" otherwise
+ int row = ui->relationListWidget->count() > 1 && ui->enumListWidget->count() > 0 ? 1 : 0;
+ ui->relationListWidget->setCurrentRow(row);
+ }
+
+ if (ftype_ != FT_NONE) {
+ ui->valueLabel->setText(QString("%1 (%2)")
+ .arg(value_label_pfx_)
+ .arg(ftype_pretty_name(ftype_)));
+ } else {
+ ui->valueLabel->setText(value_label_pfx_);
+ }
+
+ updateWidgets();
+}
+
+void DisplayFilterExpressionDialog::on_relationListWidget_itemSelectionChanged()
+{
+ updateWidgets();
+}
+
+void DisplayFilterExpressionDialog::on_enumListWidget_itemSelectionChanged()
+{
+ if (ui->enumListWidget->selectedItems().count() > 0) {
+ QListWidgetItem *eli = ui->enumListWidget->selectedItems()[0];
+ ui->valueLineEdit->setText(eli->data(Qt::UserRole).toString());
+ }
+ updateWidgets();
+}
+
+void DisplayFilterExpressionDialog::on_searchLineEdit_textChanged(const QString &search_re)
+{
+ QTreeWidgetItemIterator it(ui->fieldTreeWidget);
+ QRegExp regex(search_re, Qt::CaseInsensitive);
+ while (*it) {
+ bool hidden = true;
+ if (search_re.isEmpty() || (*it)->text(0).contains(regex)) {
+ hidden = false;
+ }
+ (*it)->setHidden(hidden);
+ ++it;
+ }
+}
+
+void DisplayFilterExpressionDialog::on_buttonBox_accepted()
+{
+ emit insertDisplayFilter(ui->displayFilterLineEdit->text());
+}
+
+void DisplayFilterExpressionDialog::on_buttonBox_helpRequested()
+{
+ wsApp->helpTopicAction(HELP_FILTER_EXPRESSION_DIALOG);
+}
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/display_filter_expression_dialog.h b/ui/qt/display_filter_expression_dialog.h
new file mode 100644
index 0000000000..0be54a02bf
--- /dev/null
+++ b/ui/qt/display_filter_expression_dialog.h
@@ -0,0 +1,86 @@
+/* display_filter_expression_dialog.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DISPLAY_FILTER_EXPRESSION_DIALOG_H
+#define DISPLAY_FILTER_EXPRESSION_DIALOG_H
+
+#include "config.h"
+
+#include <epan/ftypes/ftypes.h>
+
+#include <QDialog>
+
+class QTreeWidgetItem;
+struct true_false_string;
+struct _value_string;
+struct _val64_string;
+
+namespace Ui {
+class DisplayFilterExpressionDialog;
+}
+
+class DisplayFilterExpressionDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DisplayFilterExpressionDialog(QWidget *parent = 0);
+ ~DisplayFilterExpressionDialog();
+
+signals:
+ void insertDisplayFilter(const QString &filter);
+
+private slots:
+ void updateWidgets();
+
+ void on_fieldTreeWidget_itemSelectionChanged();
+ void on_relationListWidget_itemSelectionChanged();
+ void on_enumListWidget_itemSelectionChanged();
+ void on_searchLineEdit_textChanged(const QString &search_re);
+ void on_buttonBox_accepted();
+ void on_buttonBox_helpRequested();
+
+private:
+ Ui::DisplayFilterExpressionDialog *ui;
+ void fillEnumBooleanValues(const struct true_false_string *tfs);
+ void fillEnumIntValues(const struct _value_string *vals, int base);
+ void fillEnumInt64Values(const struct _val64_string *vals64, int base);
+ void fillEnumRangeValues(const struct _range_string *rvals);
+
+ enum ftenum ftype_;
+ const char *field_;
+ QString value_label_pfx_;
+};
+
+#endif // DISPLAY_FILTER_EXPRESSION_DIALOG_H
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/display_filter_expression_dialog.ui b/ui/qt/display_filter_expression_dialog.ui
new file mode 100644
index 0000000000..cc9ccbb8d8
--- /dev/null
+++ b/ui/qt/display_filter_expression_dialog.ui
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DisplayFilterExpressionDialog</class>
+ <widget class="QDialog" name="DisplayFilterExpressionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>657</width>
+ <height>588</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="fieldLabel">
+ <property name="toolTip">
+ <string>Select a field to start building a display filter.</string>
+ </property>
+ <property name="text">
+ <string>Field Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="fieldTreeWidget">
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="headerHidden">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="searchLabel">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Search the list of field names.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Search:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="searchLineEdit"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_6" stretch="0,1,0,4,1,0">
+ <item>
+ <layout class="QVBoxLayout" name="relationLayout">
+ <item>
+ <widget class="QLabel" name="relationLabel">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Relations can be used to restrict fields to specific values. Each relation does the following:&lt;/p&gt;
+&lt;table&gt;&lt;tbody&gt;
+&lt;tr&gt;&lt;th&gt;is present&lt;/th&gt;&lt;td&gt;Match any packet that contains this field&lt;/td&gt;&lt;/tr&gt;
+&lt;tr&gt;&lt;th&gt;==, !=, etc.&lt;/th&gt;&lt;td&gt;Compare the field to a specific value.&lt;/td&gt;&lt;/tr&gt;
+&lt;tr&gt;&lt;th&gt;contains, matches&lt;/th&gt;&lt;td&gt;Check the field against a string (contains) or a regular expression (matches)&lt;/td&gt;&lt;/tr&gt;
+&lt;/tbody&gt;&lt;/table&gt;
+&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Relation</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="relationListWidget"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>12</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="valueLayout">
+ <item>
+ <widget class="QLabel" name="valueLabel">
+ <property name="toolTip">
+ <string>Match against this value.</string>
+ </property>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="valueLineEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="enumLayout">
+ <item>
+ <widget class="QLabel" name="enumLabel">
+ <property name="toolTip">
+ <string>If the field you have selected has a known set of valid values they will be listed here.</string>
+ </property>
+ <property name="text">
+ <string>Predefined Values</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="enumListWidget"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>12</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="rangeLayout">
+ <item>
+ <widget class="QLabel" name="rangeLabel">
+ <property name="toolTip">
+ <string>If the field you have selected covers a range of bytes (e.g. you have selected a protocol) you can restrict the match to a range of bytes here.</string>
+ </property>
+ <property name="text">
+ <string>Range (offset:length)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="rangeLineEdit"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="DisplayFilterEdit" name="displayFilterLineEdit">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="placeholderText">
+ <string>No display filter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="hintLabel">
+ <property name="text">
+ <string>&lt;small&gt;&lt;i&gt;A hint.&lt;/i&gt;&lt;/small&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>DisplayFilterEdit</class>
+ <extends>QLineEdit</extends>
+ <header>display_filter_edit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>DisplayFilterExpressionDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>DisplayFilterExpressionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index d86c5c7d25..8be1b58a92 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -230,7 +230,7 @@ MainWindow::MainWindow(QWidget *parent) :
// unifiedTitleAndToolBarOnMac is enabled everything ends up in the same row.
// https://bugreports.qt-project.org/browse/QTBUG-22433
// This property is obsolete in Qt5 so this issue may be fixed in that version.
- main_ui_->displayFilterToolBar->addWidget(df_combo_box_);
+ main_ui_->displayFilterToolBar->insertWidget(main_ui_->actionDisplayFilterExpression, df_combo_box_);
main_ui_->goToFrame->hide();
// XXX For some reason the cursor is drawn funny with an input mask set
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index f4b268357b..33182dbc39 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -249,6 +249,7 @@ private slots:
void setFeaturesEnabled(bool enabled = true);
+ void on_actionDisplayFilterExpression_triggered();
void addDisplayFilterButton(QString df_text);
void displayFilterButtonClicked();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index 8e231a2c0d..060096e4ae 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -603,6 +603,7 @@
<attribute name="toolBarBreak">
<bool>true</bool>
</attribute>
+ <addaction name="actionDisplayFilterExpression"/>
</widget>
<action name="actionFileOpen">
<property name="text">
@@ -2332,6 +2333,17 @@
<string>Show expert notifications</string>
</property>
</action>
+ <action name="actionDisplayFilterExpression">
+ <property name="text">
+ <string>&amp;Expression...</string>
+ </property>
+ <property name="iconText">
+ <string>Expression...</string>
+ </property>
+ <property name="toolTip">
+ <string>Add an expression to the display filter.</string>
+ </property>
+ </action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index e883f512e4..400ef01fa5 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -81,6 +81,7 @@
#include "conversation_dialog.h"
#include "decode_as_dialog.h"
#include "display_filter_edit.h"
+#include "display_filter_expression_dialog.h"
#include "endpoint_dialog.h"
#include "expert_info_dialog.h"
#include "export_object_dialog.h"
@@ -708,12 +709,13 @@ void MainWindow::filterExpressionsChanged()
// Recreate filter buttons
foreach (QAction *act, main_ui_->displayFilterToolBar->actions()) {
// Permanent actions shouldn't have data
- if (act->property(dfe_property_).isValid()) {
+ if (act->property(dfe_property_).isValid() || act->isSeparator()) {
main_ui_->displayFilterToolBar->removeAction(act);
delete act;
}
}
+ bool first = true;
for (struct filter_expression *fe = *pfilter_expression_head; fe != NULL; fe = fe->next) {
if (!fe->enabled) continue;
QAction *dfb_action = new QAction(fe->label, main_ui_->displayFilterToolBar);
@@ -722,6 +724,10 @@ void MainWindow::filterExpressionsChanged()
dfb_action->setProperty(dfe_property_, true);
main_ui_->displayFilterToolBar->addAction(dfb_action);
connect(dfb_action, SIGNAL(triggered()), this, SLOT(displayFilterButtonClicked()));
+ if (first) {
+ first = false;
+ main_ui_->displayFilterToolBar->insertSeparator(dfb_action);
+ }
}
}
@@ -1453,6 +1459,18 @@ void MainWindow::setFeaturesEnabled(bool enabled)
}
}
+// Display Filter Toolbar
+
+void MainWindow::on_actionDisplayFilterExpression_triggered()
+{
+ DisplayFilterExpressionDialog *dfe_dialog = new DisplayFilterExpressionDialog(this);
+
+ connect(dfe_dialog, SIGNAL(insertDisplayFilter(QString)),
+ df_combo_box_->lineEdit(), SLOT(insertFilter(const QString &)));
+
+ dfe_dialog->show();
+}
+
// On Qt4 + OS X with unifiedTitleAndToolBarOnMac set it's possible to make
// the main window obnoxiously wide.
diff --git a/ui/qt/qt_ui_utils.cpp b/ui/qt/qt_ui_utils.cpp
index 297252d66c..c1dd0b6051 100644
--- a/ui/qt/qt_ui_utils.cpp
+++ b/ui/qt/qt_ui_utils.cpp
@@ -26,6 +26,7 @@
#include "qt_ui_utils.h"
#include <epan/addr_resolv.h>
+#include <epan/range.h>
#include <epan/to_str.h>
#include <epan/value_string.h>
@@ -99,6 +100,17 @@ const QString val_ext_to_qstring(const guint32 val, value_string_ext *vse, const
return val_qstr;
}
+const QString range_to_qstring(const epan_range *range)
+{
+ QString range_qstr = QString();
+ if (range) {
+ const gchar *range_gchar_p = range_convert_range(NULL, range);
+ range_qstr = range_gchar_p;
+ wmem_free(NULL, (void *) range_gchar_p);
+ }
+ return range_qstr;
+}
+
const QString bits_s_to_qstring(const double bits_s)
{
return gchar_free_to_qstring(
diff --git a/ui/qt/qt_ui_utils.h b/ui/qt/qt_ui_utils.h
index 172d05587b..66b198e9d8 100644
--- a/ui/qt/qt_ui_utils.h
+++ b/ui/qt/qt_ui_utils.h
@@ -45,30 +45,8 @@ extern "C" {
#define RECENT_KEY_CAPTURE_FILE "recent.capture_file"
#define RECENT_KEY_REMOTE_HOST "recent.remote_host"
-///* Type of capture source */
-//typedef enum {
-// CAPTURE_IFLOCAL, /**< Local network interface */
-// CAPTURE_IFREMOTE /**< Remote network interface */
-//} capture_source;
-
-///* Type of RPCAPD Authentication */
-//typedef enum {
-// CAPTURE_AUTH_NULL, /**< No authentication */
-// CAPTURE_AUTH_PWD /**< User/password authentication */
-//} capture_auth;
-
-//struct remote_host_t {
-// gchar *remote_host; /**< Host name or network address for remote capturing */
-// gchar *remote_port; /**< TCP port of remote RPCAP server */
-// gint auth_type; /**< Authentication type */
-// gchar *auth_username; /**< Remote authentication parameters */
-// gchar *auth_password; /**< Remote authentication parameters */
-// gboolean datatx_udp;
-// gboolean nocap_rpcap;
-// gboolean nocap_local;
-//};
-
struct _address;
+struct epan_range;
#ifdef __cplusplus
}
@@ -129,6 +107,14 @@ G_GNUC_PRINTF(3, 0);
const QString val_ext_to_qstring(const guint32 val, struct _value_string_ext *vse, const char *fmt)
G_GNUC_PRINTF(3, 0);
+/** Convert a range to a QString using range_convert_range().
+ *
+ * @param range A pointer to an range struct.
+ *
+ * @return A QString representation of the address. May be the null string (QString())
+ */
+const QString range_to_qstring(const struct epan_range *range);
+
/** Convert a bits per second value to a human-readable QString using format_size().
*
* @param bits_s The value to convert to string.
diff --git a/ui/qt/syntax_line_edit.cpp b/ui/qt/syntax_line_edit.cpp
index ac1b029a9f..282d969edd 100644
--- a/ui/qt/syntax_line_edit.cpp
+++ b/ui/qt/syntax_line_edit.cpp
@@ -115,6 +115,24 @@ void SyntaxLineEdit::setStyleSheet(const QString &style_sheet) {
QLineEdit::setStyleSheet(style_sheet_ + state_style_sheet_);
}
+void SyntaxLineEdit::insertFilter(const QString &filter)
+{
+ QString padded_filter = filter;
+
+ if (hasSelectedText()) {
+ backspace();
+ }
+
+ int pos = cursorPosition();
+ if (pos > 0 && !text().at(pos - 1).isSpace()) {
+ padded_filter.prepend(" ");
+ }
+ if (pos < text().length() - 1 && !text().at(pos + 1).isSpace()) {
+ padded_filter.append(" ");
+ }
+ insert(padded_filter);
+}
+
void SyntaxLineEdit::checkDisplayFilter(QString filter)
{
if (filter.isEmpty()) {
diff --git a/ui/qt/syntax_line_edit.h b/ui/qt/syntax_line_edit.h
index 585e3b59bb..c161b5fabf 100644
--- a/ui/qt/syntax_line_edit.h
+++ b/ui/qt/syntax_line_edit.h
@@ -51,6 +51,8 @@ public:
public slots:
void setStyleSheet(const QString &style_sheet);
+ // Insert filter text at the current position, adding spaces where needed.
+ void insertFilter(const QString &filter);
// Built-in syntax checks. Connect textChanged to these as needed.
void checkDisplayFilter(QString filter);