aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorAlexander Gryanko <xpahos@gmail.com>2019-02-27 07:55:52 +0300
committerAlexis La Goutte <alexis.lagoutte@gmail.com>2019-09-22 05:29:30 +0000
commit9fff62e2a8a19b94f665b2937242b65fe0ef49fc (patch)
tree0089c0553d2e6686fb9797dc17f928298caf7abc /ui
parent893a2d9c62e8dcc4fe0f43c47e01743136f55386 (diff)
Qt, http2: Add Follow HTTP/2 Stream functionality
The HTTP/2 protocol multiplexes a single TCP connection into multiple independent streams. The Follow TCP output can interleave multiple HTTP/2 streams, making it harder to analyze a single HTTP/2 stream. Add the ability to select HTTP/2 Streams within a TCP stream. Internally, the HTTP/2 dissector now stores the known Stream IDs in a set for every TCP session which allows an amortized O(n) lookup time for the previous/next/max Stream ID. [Peter: make the dissector responsible for clamping the HTTP/2 Stream ID instead of the Qt code, that should permit future optimizations.] Change-Id: I5d78f29904ae8f227ae36e1a883155c0ed719200 Reviewed-on: https://code.wireshark.org/review/32221 Reviewed-by: Peter Wu <peter@lekensteyn.nl> Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Alexander Gryanko <xpahos@gmail.com> Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Diffstat (limited to 'ui')
-rw-r--r--ui/cli/tap-follow.c23
-rw-r--r--ui/qt/follow_stream_dialog.cpp91
-rw-r--r--ui/qt/follow_stream_dialog.h5
-rw-r--r--ui/qt/follow_stream_dialog.ui16
-rw-r--r--ui/qt/main_window.h4
-rw-r--r--ui/qt/main_window.ui9
-rw-r--r--ui/qt/main_window_slots.cpp15
-rw-r--r--ui/qt/packet_list.cpp1
-rw-r--r--ui/qt/proto_tree.cpp1
-rw-r--r--ui/qt/tcp_stream_dialog.ui64
10 files changed, 180 insertions, 49 deletions
diff --git a/ui/cli/tap-follow.c b/ui/cli/tap-follow.c
index bb6380fc5a..c4d7399fd1 100644
--- a/ui/cli/tap-follow.c
+++ b/ui/cli/tap-follow.c
@@ -37,6 +37,7 @@ typedef struct _cli_follow_info {
/* filter */
int stream_index;
+ int sub_stream_index;
int port[2];
address addr[2];
union {
@@ -338,6 +339,13 @@ follow_arg_filter(const char **opt_argp, follow_info_t *follow_info)
((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
{
*opt_argp += len;
+
+ /* if it's HTTP2 protocol we should read substream id otherwise it's a range parameter from follow_arg_range */
+ if (cli_follow_info->sub_stream_index == -1 && sscanf(*opt_argp, ",%d%n", &cli_follow_info->sub_stream_index, &len) == 1 &&
+ ((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
+ {
+ *opt_argp += len;
+ }
}
else
{
@@ -438,11 +446,20 @@ static void follow_stream(const char *opt_argp, void *userdata)
register_follow_t* follower = (register_follow_t*)userdata;
follow_index_filter_func index_filter;
follow_address_filter_func address_filter;
+ int proto_id = get_follow_proto_id(follower);
+ const char* proto_filter_name = proto_get_protocol_filter_name(proto_id);
opt_argp += strlen(STR_FOLLOW);
- opt_argp += strlen(proto_get_protocol_filter_name(get_follow_proto_id(follower)));
+ opt_argp += strlen(proto_filter_name);
cli_follow_info = g_new0(cli_follow_info_t, 1);
+ cli_follow_info->stream_index = -1;
+ /* use second parameter only for HTTP2 substream */
+ if (strncmp(proto_filter_name, "http2", 5) == 0) {
+ cli_follow_info->sub_stream_index = -1;
+ } else {
+ cli_follow_info->sub_stream_index = 0;
+ }
follow_info = g_new0(follow_info_t, 1);
follow_info->gui_data = cli_follow_info;
cli_follow_info->follower = follower;
@@ -455,8 +472,8 @@ static void follow_stream(const char *opt_argp, void *userdata)
if (cli_follow_info->stream_index >= 0)
{
index_filter = get_follow_index_func(follower);
- follow_info->filter_out_filter = index_filter(cli_follow_info->stream_index);
- if (follow_info->filter_out_filter == NULL)
+ follow_info->filter_out_filter = index_filter(cli_follow_info->stream_index, cli_follow_info->sub_stream_index);
+ if (follow_info->filter_out_filter == NULL || cli_follow_info->sub_stream_index < 0)
{
follow_exit("Error creating filter for this stream.");
}
diff --git a/ui/qt/follow_stream_dialog.cpp b/ui/qt/follow_stream_dialog.cpp
index d6f96f7679..c845830420 100644
--- a/ui/qt/follow_stream_dialog.cpp
+++ b/ui/qt/follow_stream_dialog.cpp
@@ -16,6 +16,7 @@
#include "epan/follow.h"
#include "epan/dissectors/packet-tcp.h"
#include "epan/dissectors/packet-udp.h"
+#include "epan/dissectors/packet-http2.h"
#include "epan/prefs.h"
#include "epan/addr_resolv.h"
#include "epan/charsets.h"
@@ -75,7 +76,8 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
last_from_server_(0),
turns_(0),
use_regex_find_(false),
- terminating_(false)
+ terminating_(false),
+ previous_sub_stream_num_(0)
{
ui->setupUi(this);
loadGeometry(parent.width() * 2 / 3, parent.height());
@@ -94,6 +96,9 @@ FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_
case FOLLOW_HTTP:
follower_ = get_follow_by_name("HTTP");
break;
+ case FOLLOW_HTTP2:
+ follower_ = get_follow_by_name("HTTP2");
+ break;
default :
g_assert_not_reached();
}
@@ -369,8 +374,47 @@ void FollowStreamDialog::on_streamNumberSpinBox_valueChanged(int stream_num)
{
if (file_closed_) return;
+ int sub_stream_num = 0;
+ ui->subStreamNumberSpinBox->blockSignals(true);
+ sub_stream_num = ui->subStreamNumberSpinBox->value();
+ ui->subStreamNumberSpinBox->blockSignals(false);
+
+ if (sub_stream_num < 0) {
+ sub_stream_num = 0;
+ }
+
if (stream_num >= 0) {
- follow(previous_filter_, true, stream_num);
+ follow(previous_filter_, true, stream_num, sub_stream_num);
+ }
+}
+
+
+void FollowStreamDialog::on_subStreamNumberSpinBox_valueChanged(int sub_stream_num)
+{
+ if (file_closed_) return;
+
+ int stream_num = 0;
+ ui->streamNumberSpinBox->blockSignals(true);
+ stream_num = ui->streamNumberSpinBox->value();
+ ui->streamNumberSpinBox->blockSignals(false);
+
+ guint sub_stream_num_new = static_cast<guint>(sub_stream_num);
+ gboolean ok;
+ /* previous_sub_stream_num_ is a hack to track which buttons was pressed without event handling */
+ if (sub_stream_num < 0) {
+ // Stream ID 0 should always exist as it is used for control messages.
+ sub_stream_num_new = 0;
+ ok = TRUE;
+ } else if (previous_sub_stream_num_ < sub_stream_num){
+ ok = http2_get_stream_id_ge(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
+ } else {
+ ok = http2_get_stream_id_le(static_cast<guint>(stream_num), sub_stream_num_new, &sub_stream_num_new);
+ }
+ sub_stream_num = static_cast<gint>(sub_stream_num_new);
+
+ if (ok) {
+ follow(previous_filter_, true, stream_num, sub_stream_num);
+ previous_sub_stream_num_ = sub_stream_num;
}
}
@@ -388,6 +432,8 @@ void FollowStreamDialog::removeStreamControls()
ui->horizontalLayout->removeItem(ui->streamNumberSpacer);
ui->streamNumberLabel->setVisible(false);
ui->streamNumberSpinBox->setVisible(false);
+ ui->subStreamNumberLabel->setVisible(false);
+ ui->subStreamNumberSpinBox->setVisible(false);
}
void FollowStreamDialog::resetStream()
@@ -455,6 +501,7 @@ FollowStreamDialog::readStream()
case FOLLOW_TCP :
case FOLLOW_UDP :
case FOLLOW_HTTP :
+ case FOLLOW_HTTP2:
case FOLLOW_TLS :
ret = readFollowStream();
break;
@@ -771,7 +818,7 @@ FollowStreamDialog::showBuffer(char *buffer, size_t nchars, gboolean is_from_ser
return FRS_OK;
}
-bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index, guint stream_num)
+bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index, guint stream_num, guint sub_stream_num)
{
QString follow_filter;
const char *hostname0 = NULL, *hostname1 = NULL;
@@ -815,9 +862,9 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
/* Create a new filter that matches all packets in the TCP stream,
and set the display filter entry accordingly */
if (use_stream_index) {
- follow_filter = gchar_free_to_qstring(get_follow_index_func(follower_)(stream_num));
+ follow_filter = gchar_free_to_qstring(get_follow_index_func(follower_)(stream_num, sub_stream_num));
} else {
- follow_filter = gchar_free_to_qstring(get_follow_conv_func(follower_)(&cap_file_.capFile()->edt->pi, &stream_num));
+ follow_filter = gchar_free_to_qstring(get_follow_conv_func(follower_)(&cap_file_.capFile()->edt->pi, &stream_num, &sub_stream_num));
}
if (follow_filter.isEmpty()) {
QMessageBox::warning(this,
@@ -844,6 +891,15 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
return false;
}
+ /* disable substream spin box for all protocols except HTTP2 */
+ ui->subStreamNumberSpinBox->blockSignals(true);
+ ui->subStreamNumberSpinBox->setEnabled(false);
+ ui->subStreamNumberSpinBox->setValue(0);
+ ui->subStreamNumberSpinBox->setKeyboardTracking(false);
+ ui->subStreamNumberSpinBox->blockSignals(false);
+ ui->subStreamNumberSpinBox->setVisible(false);
+ ui->subStreamNumberLabel->setVisible(false);
+
switch (follow_type_)
{
case FOLLOW_TCP:
@@ -870,6 +926,31 @@ bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index,
break;
}
+ case FOLLOW_HTTP2:
+ {
+ int stream_count = get_tcp_stream_count();
+ ui->streamNumberSpinBox->blockSignals(true);
+ ui->streamNumberSpinBox->setMaximum(stream_count-1);
+ ui->streamNumberSpinBox->setValue(stream_num);
+ ui->streamNumberSpinBox->blockSignals(false);
+ ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
+ ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
+
+ guint substream_max_id = 0;
+ http2_get_stream_id_le(static_cast<guint>(stream_num), G_MAXINT32, &substream_max_id);
+ stream_count = static_cast<gint>(substream_max_id);
+ ui->subStreamNumberSpinBox->blockSignals(true);
+ ui->subStreamNumberSpinBox->setEnabled(true);
+ ui->subStreamNumberSpinBox->setMaximum(stream_count);
+ ui->subStreamNumberSpinBox->setValue(sub_stream_num);
+ ui->subStreamNumberSpinBox->blockSignals(false);
+ ui->subStreamNumberSpinBox->setToolTip(tr("%Ln total sub stream(s).", "", stream_count));
+ ui->subStreamNumberSpinBox->setToolTip(ui->subStreamNumberSpinBox->toolTip());
+ ui->subStreamNumberSpinBox->setVisible(true);
+ ui->subStreamNumberLabel->setVisible(true);
+
+ break;
+ }
case FOLLOW_TLS:
case FOLLOW_HTTP:
/* No extra handling */
diff --git a/ui/qt/follow_stream_dialog.h b/ui/qt/follow_stream_dialog.h
index 4988092a6c..a2c3928fae 100644
--- a/ui/qt/follow_stream_dialog.h
+++ b/ui/qt/follow_stream_dialog.h
@@ -42,7 +42,7 @@ public:
explicit FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_type_t type = FOLLOW_TCP);
~FollowStreamDialog();
- bool follow(QString previous_filter = QString(), bool use_stream_index = false, guint stream_num = 0);
+ bool follow(QString previous_filter = QString(), bool use_stream_index = false, guint stream_num = 0, guint sub_stream_num = 0);
public slots:
void captureEvent(CaptureEvent e);
@@ -69,6 +69,7 @@ private slots:
void goToPacketForTextPos(int text_pos);
void on_streamNumberSpinBox_valueChanged(int stream_num);
+ void on_subStreamNumberSpinBox_valueChanged(int sub_stream_num);
void on_buttonBox_rejected();
@@ -122,6 +123,8 @@ private:
bool use_regex_find_;
bool terminating_;
+
+ int previous_sub_stream_num_;
};
#endif // FOLLOW_STREAM_DIALOG_H
diff --git a/ui/qt/follow_stream_dialog.ui b/ui/qt/follow_stream_dialog.ui
index 066b90b857..2d70316471 100644
--- a/ui/qt/follow_stream_dialog.ui
+++ b/ui/qt/follow_stream_dialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>594</width>
- <height>620</height>
+ <width>609</width>
+ <height>600</height>
</rect>
</property>
<property name="sizePolicy">
@@ -41,7 +41,7 @@
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,0,0">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,0,0,0,0">
<item>
<widget class="QComboBox" name="cbDirections">
<property name="sizeAdjustPolicy">
@@ -99,6 +99,16 @@
<item>
<widget class="QSpinBox" name="streamNumberSpinBox"/>
</item>
+ <item>
+ <widget class="QLabel" name="subStreamNumberLabel">
+ <property name="text">
+ <string>Substream</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="subStreamNumberSpinBox"/>
+ </item>
</layout>
</item>
<item>
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index 2be67fbe16..a5d8077012 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -543,12 +543,14 @@ private slots:
void on_actionAnalyzeDecodeAs_triggered();
void on_actionAnalyzeReloadLuaPlugins_triggered();
- void openFollowStreamDialog(follow_type_t type, guint stream_num, bool use_stream_index = true);
+ void openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index = true);
void openFollowStreamDialogForType(follow_type_t type);
void on_actionAnalyzeFollowTCPStream_triggered();
void on_actionAnalyzeFollowUDPStream_triggered();
void on_actionAnalyzeFollowTLSStream_triggered();
void on_actionAnalyzeFollowHTTPStream_triggered();
+ void on_actionAnalyzeFollowHTTP2Stream_triggered();
+
void statCommandExpertInfo(const char *, void *);
void on_actionAnalyzeExpertInfo_triggered();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index 1f03a535dc..06ffdd1df4 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -415,6 +415,7 @@
<addaction name="actionAnalyzeFollowUDPStream"/>
<addaction name="actionAnalyzeFollowTLSStream"/>
<addaction name="actionAnalyzeFollowHTTPStream"/>
+ <addaction name="actionAnalyzeFollowHTTP2Stream"/>
</widget>
<widget class="QMenu" name="menuConversationFilter">
<property name="title">
@@ -1711,6 +1712,14 @@
<string notr="true">Ctrl+Alt+Shift+H</string>
</property>
</action>
+ <action name="actionAnalyzeFollowHTTP2Stream">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>HTTP/2 Stream</string>
+ </property>
+ </action>
<action name="actionStatisticsTcpStreamTcptrace">
<property name="text">
<string>Time Sequence (tcptrace)</string>
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index 3516730475..a164c20865 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -1114,7 +1114,7 @@ void MainWindow::recentActionTriggered() {
void MainWindow::setMenusForSelectedPacket()
{
- gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE, is_http = FALSE;
+ gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_tls = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE, is_http = FALSE, is_http2 = FALSE;
/* Making the menu context-sensitive allows for easier selection of the
desired item and has the added benefit, with large captures, of
@@ -1173,6 +1173,7 @@ void MainWindow::setMenusForSelectedPacket()
&is_ip, &is_tcp, &is_udp, &is_sctp,
&is_tls, &is_rtp, &is_lte_rlc);
is_http = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http");
+ is_http2 = proto_is_frame_protocol(capture_file_.capFile()->edt->pi.layers, "http2");
}
}
@@ -1205,6 +1206,7 @@ void MainWindow::setMenusForSelectedPacket()
main_ui_->actionAnalyzeFollowUDPStream->setEnabled(is_udp);
main_ui_->actionAnalyzeFollowTLSStream->setEnabled(is_tls);
main_ui_->actionAnalyzeFollowHTTPStream->setEnabled(is_http);
+ main_ui_->actionAnalyzeFollowHTTP2Stream->setEnabled(is_http2);
foreach(QAction *cc_action, cc_actions) {
cc_action->setEnabled(frame_selected);
@@ -2697,7 +2699,7 @@ void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered()
reloadLuaPlugins();
}
-void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, bool use_stream_index) {
+void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, guint sub_stream_num, bool use_stream_index) {
FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type);
connect(fsd, SIGNAL(updateFilter(QString, bool)), this, SLOT(filterPackets(QString, bool)));
connect(fsd, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int)));
@@ -2706,14 +2708,14 @@ void MainWindow::openFollowStreamDialog(follow_type_t type, guint stream_num, bo
if (use_stream_index) {
// If a specific conversation was requested, then ignore any previous
// display filters and display all related packets.
- fsd->follow("", true, stream_num);
+ fsd->follow("", true, stream_num, sub_stream_num);
} else {
fsd->follow(getFilter());
}
}
void MainWindow::openFollowStreamDialogForType(follow_type_t type) {
- openFollowStreamDialog(type, 0, false);
+ openFollowStreamDialog(type, 0, 0, false);
}
void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
@@ -2736,6 +2738,11 @@ void MainWindow::on_actionAnalyzeFollowHTTPStream_triggered()
openFollowStreamDialogForType(FOLLOW_HTTP);
}
+void MainWindow::on_actionAnalyzeFollowHTTP2Stream_triggered()
+{
+ openFollowStreamDialogForType(FOLLOW_HTTP2);
+}
+
void MainWindow::openSCTPAllAssocsDialog()
{
SCTPAllAssocsDialog *sctp_dialog = new SCTPAllAssocsDialog(this, capture_file_.capFile());
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index 3304fe362c..bc8ffc287a 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -543,6 +543,7 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
+ submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
ctx_menu->addSeparator();
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index d23c0879aa..bc72ca7b3d 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -285,6 +285,7 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTLSStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTPStream"));
+ submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowHTTP2Stream"));
ctx_menu.addSeparator();
}
diff --git a/ui/qt/tcp_stream_dialog.ui b/ui/qt/tcp_stream_dialog.ui
index d21074818e..d732f2665e 100644
--- a/ui/qt/tcp_stream_dialog.ui
+++ b/ui/qt/tcp_stream_dialog.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>850</width>
+ <width>969</width>
<height>640</height>
</rect>
</property>
@@ -90,12 +90,12 @@
</item>
<item>
<widget class="QComboBox" name="graphTypeComboBox">
- <property name="frame">
- <bool>false</bool>
- </property>
<property name="focusPolicy">
<enum>Qt::TabFocus</enum>
</property>
+ <property name="frame">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -119,19 +119,19 @@
</widget>
</item>
<item>
- <widget class="QDoubleSpinBox" name="maWindowSizeSpinBox" />
+ <widget class="QDoubleSpinBox" name="maWindowSizeSpinBox"/>
</item>
<item>
<widget class="QCheckBox" name="selectSACKsCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Allow SACK segments as well as data packets to be selected by clicking on the graph</string>
</property>
<property name="text">
<string>Select SACKs</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>
@@ -180,6 +180,9 @@
</item>
<item>
<widget class="QRadioButton" name="dragRadioButton">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Drag using the mouse button.</string>
</property>
@@ -189,9 +192,6 @@
<property name="checkable">
<bool>true</bool>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
<attribute name="buttonGroup">
<string notr="true">mouseButtonGroup</string>
</attribute>
@@ -199,6 +199,9 @@
</item>
<item>
<widget class="QRadioButton" name="zoomRadioButton">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Select using the mouse button.</string>
</property>
@@ -208,9 +211,6 @@
<property name="checkable">
<bool>true</bool>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
<attribute name="buttonGroup">
<string notr="true">mouseButtonGroup</string>
</attribute>
@@ -231,80 +231,80 @@
</item>
<item>
<widget class="QCheckBox" name="bySeqNumberCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Display Round Trip Time vs Sequence Number</string>
</property>
<property name="text">
<string>RTT By Sequence Number</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showSegLengthCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Display graph of Segment Length vs Time</string>
</property>
<property name="text">
<string>Segment Length</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showThroughputCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Display graph of Mean Transmitted Bytes vs Time</string>
</property>
<property name="text">
<string>Throughput</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showGoodputCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Display graph of Mean ACKed Bytes vs Time</string>
</property>
<property name="text">
<string>Goodput</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showRcvWinCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Display graph of Receive Window Size vs Time</string>
</property>
<property name="text">
<string>Rcv Win</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showBytesOutCheckBox">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
<property name="toolTip">
<string>Display graph of Outstanding Bytes vs Time</string>
</property>
<property name="text">
<string>Bytes Out</string>
</property>
- <property name="focusPolicy">
- <enum>Qt::TabFocus</enum>
- </property>
</widget>
</item>
<item>