forked from osmocom/wireshark
Qt: add SACK graphs to tcptrace graph
Primarily, this adds visual indication of SACK blocks to tcptrace. In addition: - cleaned up focus behavior for graph selector and spinboxes - added time-delay update to streamNumber spinBox (similar to behavior of maWindow spinBox) - changed ACK selection to select only SACKed responses (rather than all ACKs - SACKs seemed more useful to look at) Change-Id: I47d9e98d54f14e4955008ecea791b77f805c8ba9 Reviewed-on: https://code.wireshark.org/review/19388 Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com> Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
15ad25ecb5
commit
3fae1366d1
|
@ -64,7 +64,8 @@ const int moving_avg_period_ = 20;
|
|||
const QRgb graph_color_1 = tango_sky_blue_5;
|
||||
const QRgb graph_color_2 = tango_butter_6;
|
||||
const QRgb graph_color_3 = tango_chameleon_5;
|
||||
//const QRgb graph_color_4 = tango_aluminium_6;
|
||||
const QRgb graph_color_4 = tango_scarlet_red_4;
|
||||
const QRgb graph_color_5 = tango_scarlet_red_6;
|
||||
|
||||
// Size of selectable packet points in the base graph
|
||||
const double pkt_point_size_ = 3.0;
|
||||
|
@ -98,7 +99,7 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
|
|||
packet_num_(0),
|
||||
mouse_drags_(true),
|
||||
rubber_band_(NULL),
|
||||
graph_update_timer_(NULL),
|
||||
graph_updater_(this),
|
||||
num_dsegs_(-1),
|
||||
num_acks_(-1),
|
||||
num_sack_ranges_(-1),
|
||||
|
@ -210,21 +211,43 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
|
|||
sp->plotLayout()->insertRow(0);
|
||||
sp->plotLayout()->addElement(0, 0, title_);
|
||||
|
||||
base_graph_ = sp->addGraph(); // All: Selectable segments
|
||||
// Base Graph - enables selecting segments (both data and SACKs)
|
||||
base_graph_ = sp->addGraph();
|
||||
base_graph_->setPen(QPen(QBrush(graph_color_1), 0.25));
|
||||
tput_graph_ = sp->addGraph(sp->xAxis, sp->yAxis2); // Throughput: Moving average
|
||||
// Throughput Graph
|
||||
tput_graph_ = sp->addGraph(sp->xAxis, sp->yAxis2);
|
||||
tput_graph_->setPen(QPen(QBrush(graph_color_2), 0.5));
|
||||
tput_graph_->setLineStyle(QCPGraph::lsStepLeft);
|
||||
seg_graph_ = sp->addGraph(); // tcptrace: fwd segments
|
||||
// Seg Graph - displays forward data segments on tcptrace graph
|
||||
seg_graph_ = sp->addGraph();
|
||||
seg_graph_->setErrorType(QCPGraph::etValue);
|
||||
seg_graph_->setLineStyle(QCPGraph::lsNone);
|
||||
seg_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDot, Qt::transparent, 0));
|
||||
seg_graph_->setErrorPen(QPen(QBrush(graph_color_1), 0.5));
|
||||
seg_graph_->setErrorBarSkipSymbol(false); // draw error spine as single line
|
||||
seg_graph_->setErrorBarSize(pkt_point_size_);
|
||||
ack_graph_ = sp->addGraph(); // tcptrace: rev ACKs
|
||||
// Ack Graph - displays ack numbers from reverse packets
|
||||
ack_graph_ = sp->addGraph();
|
||||
ack_graph_->setPen(QPen(QBrush(graph_color_2), 0.5));
|
||||
ack_graph_->setLineStyle(QCPGraph::lsStepLeft);
|
||||
rwin_graph_ = sp->addGraph(); // tcptrace: rev RWIN
|
||||
// Sack Graph - displays highest number (most recent) SACK block
|
||||
sack_graph_ = sp->addGraph();
|
||||
sack_graph_->setErrorType(QCPGraph::etValue);
|
||||
sack_graph_->setLineStyle(QCPGraph::lsNone);
|
||||
sack_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDot, Qt::transparent, 0));
|
||||
sack_graph_->setErrorPen(QPen(QBrush(graph_color_4), 0.5));
|
||||
sack_graph_->setErrorBarSkipSymbol(false);
|
||||
sack_graph_->setErrorBarSize(0.0);
|
||||
// Sack Graph 2 - displays subsequent SACK blocks
|
||||
sack2_graph_ = sp->addGraph();
|
||||
sack2_graph_->setErrorType(QCPGraph::etValue);
|
||||
sack2_graph_->setLineStyle(QCPGraph::lsNone);
|
||||
sack2_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDot, Qt::transparent, 0));
|
||||
sack2_graph_->setErrorPen(QPen(QBrush(graph_color_5), 0.5));
|
||||
sack2_graph_->setErrorBarSkipSymbol(false);
|
||||
sack2_graph_->setErrorBarSize(0.0);
|
||||
// RWin graph - displays upper extent of RWIN advertised on reverse packets
|
||||
rwin_graph_ = sp->addGraph();
|
||||
rwin_graph_->setPen(QPen(QBrush(graph_color_3), 0.5));
|
||||
rwin_graph_->setLineStyle(QCPGraph::lsStepLeft);
|
||||
|
||||
|
@ -276,13 +299,16 @@ void TCPStreamDialog::keyPressEvent(QKeyEvent *event)
|
|||
{
|
||||
int pan_pixels = event->modifiers() & Qt::ShiftModifier ? 1 : 10;
|
||||
|
||||
if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) &&
|
||||
ui->maWindowSizeSpinBox->hasFocus()) {
|
||||
QWidget* focusWidget = QApplication::focusWidget();
|
||||
|
||||
// If user was editing maWindowSize, then just use the new value
|
||||
// clear the focus and accept the event
|
||||
// (don't propagate to default close button)
|
||||
ui->maWindowSizeSpinBox->clearFocus();
|
||||
// Block propagation of "Enter" key when focus is not default (e.g. SpinBox)
|
||||
// [ Note that if focus was on, e.g. Close button, event would never reach
|
||||
// here ]
|
||||
if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) &&
|
||||
focusWidget !=NULL && focusWidget != ui->streamPlot) {
|
||||
|
||||
// reset focus to default, and accept event
|
||||
ui->streamPlot->setFocus();
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
@ -395,10 +421,18 @@ void TCPStreamDialog::findStream()
|
|||
QCustomPlot *sp = ui->streamPlot;
|
||||
|
||||
disconnect(sp, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMoved(QMouseEvent*)));
|
||||
// if streamNumberSpinBox has focus -
|
||||
// first clear focus, then disable/enable, then restore focus
|
||||
bool spin_box_focused = ui->streamNumberSpinBox->hasFocus();
|
||||
if (spin_box_focused)
|
||||
ui->streamNumberSpinBox->clearFocus();
|
||||
ui->streamNumberSpinBox->setEnabled(false);
|
||||
graph_segment_list_free(&graph_);
|
||||
graph_segment_list_get(cap_file_, &graph_, TRUE);
|
||||
ui->streamNumberSpinBox->setEnabled(true);
|
||||
if (spin_box_focused)
|
||||
ui->streamNumberSpinBox->setFocus();
|
||||
|
||||
connect(sp, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMoved(QMouseEvent*)));
|
||||
}
|
||||
|
||||
|
@ -450,9 +484,12 @@ void TCPStreamDialog::fillGraph(bool reset_axes, bool set_focus)
|
|||
// NOTE - adding both forward and reverse packets to time_stamp_map_
|
||||
// so that both data and acks are selectable
|
||||
// (this is important especially in selecting particular SACK pkts)
|
||||
bool insert = true;
|
||||
if (!compareHeaders(seg)) {
|
||||
bytes_rev += seg->th_seglen;
|
||||
pkts_rev++;
|
||||
// only insert reverse packets if SACK present
|
||||
insert = (seg->num_sack_ranges != 0);
|
||||
} else {
|
||||
bytes_fwd += seg->th_seglen;
|
||||
pkts_fwd++;
|
||||
|
@ -468,7 +505,9 @@ void TCPStreamDialog::fillGraph(bool reset_axes, bool set_focus)
|
|||
}
|
||||
first = false;
|
||||
}
|
||||
time_stamp_map_.insertMulti(ts - ts_offset_, seg);
|
||||
if (insert) {
|
||||
time_stamp_map_.insertMulti(ts - ts_offset_, seg);
|
||||
}
|
||||
}
|
||||
|
||||
switch (graph_.type) {
|
||||
|
@ -527,9 +566,9 @@ void TCPStreamDialog::showWidgetsForGraphType()
|
|||
#endif
|
||||
|
||||
if (graph_.type == GRAPH_TSEQ_TCPTRACE) {
|
||||
ui->selectAcksCheckBox->setVisible(true);
|
||||
ui->selectSACKsCheckBox->setVisible(true);
|
||||
} else {
|
||||
ui->selectAcksCheckBox->setVisible(false);
|
||||
ui->selectSACKsCheckBox->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -654,7 +693,7 @@ void TCPStreamDialog::fillTcptrace()
|
|||
setWindowTitle(dlg_title);
|
||||
title_->setText(dlg_title);
|
||||
|
||||
bool allow_ack_select = ui->selectAcksCheckBox->isChecked();
|
||||
bool allow_sack_select = ui->selectSACKsCheckBox->isChecked();
|
||||
|
||||
QCustomPlot *sp = ui->streamPlot;
|
||||
sp->yAxis->setLabel(sequence_number_label_);
|
||||
|
@ -663,23 +702,32 @@ void TCPStreamDialog::fillTcptrace()
|
|||
|
||||
seg_graph_->setVisible(true);
|
||||
ack_graph_->setVisible(true);
|
||||
sack_graph_->setVisible(true);
|
||||
sack2_graph_->setVisible(true);
|
||||
rwin_graph_->setVisible(true);
|
||||
|
||||
QVector<double> pkt_time, pkt_seqnums, sb_time, sb_center, sb_span, ackrwin_time, ack, rwin;
|
||||
QVector<double> pkt_time, pkt_seqnums;
|
||||
QVector<double> sb_time, sb_center, sb_span;
|
||||
QVector<double> ackrwin_time, ack, rwin;
|
||||
QVector<double> sack_time, sack_center, sack_span;
|
||||
QVector<double> sack2_time, sack2_center, sack2_span;
|
||||
|
||||
for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) {
|
||||
double ts = (seg->rel_secs + seg->rel_usecs / 1000000.0) - ts_offset_;
|
||||
if (compareHeaders(seg)) {
|
||||
double half = seg->th_seglen / 2.0;
|
||||
double center = seg->th_seq - seq_offset_ + half;
|
||||
|
||||
// Add forward direction to base_graph_ (to select data packets)
|
||||
// Forward direction: seq + data
|
||||
pkt_time.append(ts);
|
||||
pkt_seqnums.append(seg->th_seq - seq_offset_);
|
||||
pkt_seqnums.append(center);
|
||||
|
||||
// QCP doesn't have a segment graph type. For now, fake
|
||||
// it with error bars.
|
||||
if (seg->th_seglen > 0) {
|
||||
double half = seg->th_seglen / 2.0;
|
||||
sb_time.append(ts);
|
||||
sb_center.append(seg->th_seq - seq_offset_ + half);
|
||||
sb_center.append(center);
|
||||
sb_span.append(half);
|
||||
}
|
||||
} else {
|
||||
|
@ -689,10 +737,24 @@ void TCPStreamDialog::fillTcptrace()
|
|||
continue;
|
||||
}
|
||||
double ackno = seg->th_ack - seq_offset_;
|
||||
if (allow_ack_select) {
|
||||
// Add reverse direction to base_graph_ (to select ACK packets)
|
||||
pkt_time.append(ts);
|
||||
pkt_seqnums.append(ackno);
|
||||
// add SACK segments to sack, sack2, and selectable packet graph
|
||||
for (int i = 0; i < seg->num_sack_ranges; ++i) {
|
||||
double half = seg->sack_right_edge[i] - seg->sack_left_edge[i];
|
||||
half = half/2.0;
|
||||
double center = seg->sack_left_edge[i] - seq_offset_ + half;
|
||||
if (i == 0) {
|
||||
sack_time.append(ts);
|
||||
sack_center.append(center);
|
||||
sack_span.append(half);
|
||||
if (allow_sack_select) {
|
||||
pkt_time.append(ts);
|
||||
pkt_seqnums.append(center);
|
||||
}
|
||||
} else {
|
||||
sack2_time.append(ts);
|
||||
sack2_center.append(center);
|
||||
sack2_span.append(half);
|
||||
}
|
||||
}
|
||||
// Also add reverse packets to the ack_graph_
|
||||
ackrwin_time.append(ts);
|
||||
|
@ -703,6 +765,8 @@ void TCPStreamDialog::fillTcptrace()
|
|||
base_graph_->setData(pkt_time, pkt_seqnums);
|
||||
seg_graph_->setDataValueError(sb_time, sb_center, sb_span);
|
||||
ack_graph_->setData(ackrwin_time, ack);
|
||||
sack_graph_->setDataValueError(sack_time, sack_center, sack_span);
|
||||
sack2_graph_->setDataValueError(sack2_time, sack2_center, sack2_span);
|
||||
rwin_graph_->setData(ackrwin_time, rwin);
|
||||
}
|
||||
|
||||
|
@ -1177,7 +1241,8 @@ void TCPStreamDialog::on_graphTypeComboBox_currentIndexChanged(int index)
|
|||
if (index < 0) return;
|
||||
graph_.type = static_cast<tcp_graph_type>(ui->graphTypeComboBox->itemData(index).toInt());
|
||||
showWidgetsForGraphType();
|
||||
fillGraph();
|
||||
|
||||
fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_resetButton_clicked()
|
||||
|
@ -1194,51 +1259,37 @@ void TCPStreamDialog::setCaptureFile(capture_file *cf)
|
|||
|
||||
void TCPStreamDialog::updateGraph()
|
||||
{
|
||||
|
||||
// graph_update_timer_ is created only when there's a pending
|
||||
// parameter change, and deleted when an update consumes that change.
|
||||
// Therefore lack of an update timer means nothing to update.
|
||||
if (graph_update_timer_) {
|
||||
if (graph_update_timer_->isActive())
|
||||
graph_update_timer_->stop();
|
||||
delete graph_update_timer_;
|
||||
graph_update_timer_ = NULL;
|
||||
fillGraph(/*reset_axes=*/false, /*set_focus=*/false);
|
||||
}
|
||||
graph_updater_.doUpdate();
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_streamNumberSpinBox_valueChanged(int new_stream)
|
||||
{
|
||||
if (new_stream >= 0 && new_stream < int(get_tcp_stream_count())) {
|
||||
graph_.stream = new_stream;
|
||||
clear_address(&graph_.src_address);
|
||||
clear_address(&graph_.dst_address);
|
||||
findStream();
|
||||
fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
|
||||
graph_updater_.triggerUpdate(1000, /*reset_axes =*/true);
|
||||
}
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_streamNumberSpinBox_editingFinished()
|
||||
{
|
||||
updateGraph();
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_maWindowSizeSpinBox_valueChanged(double new_ma_size)
|
||||
{
|
||||
if (new_ma_size > 0.0) {
|
||||
ma_window_size_ = new_ma_size;
|
||||
if (!graph_update_timer_) {
|
||||
graph_update_timer_ = new QTimer(this);
|
||||
graph_update_timer_->setSingleShot(true);
|
||||
connect(graph_update_timer_, SIGNAL(timeout()), this, SLOT(updateGraph()));
|
||||
}
|
||||
graph_update_timer_->start(1000);
|
||||
graph_updater_.triggerUpdate(1000, /*reset_axes =*/false);
|
||||
}
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_maWindowSizeSpinBox_editingFinished()
|
||||
{
|
||||
updateGraph();
|
||||
updateGraph();
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_selectAcksCheckBox_stateChanged(int /* state */)
|
||||
void TCPStreamDialog::on_selectSACKsCheckBox_stateChanged(int /* state */)
|
||||
{
|
||||
fillGraph(/*reset_axes=*/false, /*set_focus=*/true);
|
||||
fillGraph(/*reset_axes=*/false, /*set_focus=*/false);
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_otherDirectionButton_clicked()
|
||||
|
@ -1340,6 +1391,7 @@ void TCPStreamDialog::on_actionNextStream_triggered()
|
|||
{
|
||||
if (int(graph_.stream) < int(get_tcp_stream_count()) - 1) {
|
||||
ui->streamNumberSpinBox->setValue(graph_.stream + 1);
|
||||
updateGraph();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1347,6 +1399,7 @@ void TCPStreamDialog::on_actionPreviousStream_triggered()
|
|||
{
|
||||
if (graph_.stream > 0) {
|
||||
ui->streamNumberSpinBox->setValue(graph_.stream - 1);
|
||||
updateGraph();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1362,7 +1415,7 @@ void TCPStreamDialog::on_actionSwitchDirection_triggered()
|
|||
copy_address(&graph_.dst_address, &tmp_addr);
|
||||
graph_.dst_port = tmp_port;
|
||||
|
||||
fillGraph();
|
||||
fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
|
||||
}
|
||||
|
||||
void TCPStreamDialog::on_actionGoToPacket_triggered()
|
||||
|
@ -1418,6 +1471,45 @@ void TCPStreamDialog::on_actionWindowScaling_triggered()
|
|||
ui->graphTypeComboBox->setCurrentIndex(ui->graphTypeComboBox->findData(GRAPH_WSCALE));
|
||||
}
|
||||
|
||||
void TCPStreamDialog::GraphUpdater::triggerUpdate(int timeout, bool reset_axes)
|
||||
{
|
||||
if (!hasPendingUpdate()) {
|
||||
graph_update_timer_ = new QTimer(dialog_);
|
||||
graph_update_timer_->setSingleShot(true);
|
||||
dialog_->connect(graph_update_timer_, SIGNAL(timeout()), dialog_, SLOT(updateGraph()));
|
||||
}
|
||||
reset_axes_ = (reset_axes || reset_axes);
|
||||
graph_update_timer_->start(timeout);
|
||||
}
|
||||
|
||||
void TCPStreamDialog::GraphUpdater::clearPendingUpdate()
|
||||
{
|
||||
if (hasPendingUpdate()) {
|
||||
if (graph_update_timer_->isActive())
|
||||
graph_update_timer_->stop();
|
||||
delete graph_update_timer_;
|
||||
graph_update_timer_ = NULL;
|
||||
reset_axes_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TCPStreamDialog::GraphUpdater::doUpdate()
|
||||
{
|
||||
if (hasPendingUpdate()) {
|
||||
bool reset_axes = reset_axes_;
|
||||
clearPendingUpdate();
|
||||
// if the stream has changed, update the data here
|
||||
int new_stream = dialog_->ui->streamNumberSpinBox->value();
|
||||
if ((int(dialog_->graph_.stream) != new_stream) &&
|
||||
(new_stream >= 0 && new_stream < int(get_tcp_stream_count()))) {
|
||||
dialog_->graph_.stream = new_stream;
|
||||
clear_address(&dialog_->graph_.src_address);
|
||||
clear_address(&dialog_->graph_.dst_address);
|
||||
dialog_->findStream();
|
||||
}
|
||||
dialog_->fillGraph(reset_axes, /*set_focus =*/false);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
|
|
|
@ -78,6 +78,8 @@ private:
|
|||
QCPGraph *tput_graph_;
|
||||
QCPGraph *seg_graph_;
|
||||
QCPGraph *ack_graph_;
|
||||
QCPGraph *sack_graph_;
|
||||
QCPGraph *sack2_graph_;
|
||||
QCPGraph *rwin_graph_;
|
||||
QCPItemTracer *tracer_;
|
||||
QRectF axis_bounds_;
|
||||
|
@ -87,7 +89,24 @@ private:
|
|||
QRubberBand *rubber_band_;
|
||||
QPoint rb_origin_;
|
||||
QMenu ctx_menu_;
|
||||
QTimer *graph_update_timer_;
|
||||
|
||||
class GraphUpdater {
|
||||
public:
|
||||
GraphUpdater(TCPStreamDialog *dialog) :
|
||||
dialog_(dialog),
|
||||
graph_update_timer_(NULL),
|
||||
reset_axes_(false) {}
|
||||
void triggerUpdate(int timeout, bool reset_axes = false);
|
||||
void clearPendingUpdate();
|
||||
void doUpdate();
|
||||
bool hasPendingUpdate() { return graph_update_timer_ != NULL; }
|
||||
private:
|
||||
TCPStreamDialog *dialog_;
|
||||
QTimer *graph_update_timer_;
|
||||
bool reset_axes_;
|
||||
};
|
||||
friend class GraphUpdater;
|
||||
GraphUpdater graph_updater_;
|
||||
|
||||
int num_dsegs_;
|
||||
int num_acks_;
|
||||
|
@ -123,9 +142,10 @@ private slots:
|
|||
void on_graphTypeComboBox_currentIndexChanged(int index);
|
||||
void on_resetButton_clicked();
|
||||
void on_streamNumberSpinBox_valueChanged(int new_stream);
|
||||
void on_streamNumberSpinBox_editingFinished();
|
||||
void on_maWindowSizeSpinBox_valueChanged(double new_ma_size);
|
||||
void on_maWindowSizeSpinBox_editingFinished();
|
||||
void on_selectAcksCheckBox_stateChanged(int state);
|
||||
void on_selectSACKsCheckBox_stateChanged(int state);
|
||||
void on_otherDirectionButton_clicked();
|
||||
void on_dragRadioButton_toggled(bool checked);
|
||||
void on_zoomRadioButton_toggled(bool checked);
|
||||
|
|
|
@ -89,7 +89,14 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="graphTypeComboBox"/>
|
||||
<widget class="QComboBox" name="graphTypeComboBox">
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="maWindowSizeLabel">
|
||||
|
@ -102,12 +109,15 @@
|
|||
<widget class="QDoubleSpinBox" name="maWindowSizeSpinBox" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="selectAcksCheckBox">
|
||||
<widget class="QCheckBox" name="selectSACKsCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>Allow ACKs as well as data packets to be selected by clicking on the graph</string>
|
||||
<string>Allow SACK segments as well as data packets to be selected by clicking on the graph</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>select ACKs</string>
|
||||
<string>select SACKs</string>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -166,6 +176,9 @@
|
|||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">mouseButtonGroup</string>
|
||||
</attribute>
|
||||
|
@ -182,6 +195,9 @@
|
|||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">mouseButtonGroup</string>
|
||||
</attribute>
|
||||
|
|
Loading…
Reference in New Issue