Qt: Add Time and Comment labels to the sequence diagram.
Add "Time" and "Comment" labels to the sequence diagram similar to the GTK+ UI. Draw a border around the diagram as well. Widen the default spacing and set it to a simple em-width multiple. Fix our port number alignment. Copy over the sequence diagram colors from the GTK+ UI and add them to ColorUtils. Color sequences according to their respective conversation numbers. To do: - Add zoom. Ping-Bug: 12419 Change-Id: I3f9b4ffbfcc34aae1c38e303cd36ff207be247b1 Reviewed-on: https://code.wireshark.org/review/15554 Reviewed-by: Gerald Combs <gerald@wireshark.org> Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
bf628988b6
commit
6952c1342a
|
@ -31,24 +31,6 @@ const QColor ColorUtils::expert_color_error = QColor ( 0xff, 0x5c, 0x5c );
|
|||
const QColor ColorUtils::expert_color_foreground = QColor ( 0x00, 0x00, 0x00 ); /* Black */
|
||||
const QColor ColorUtils::hidden_proto_item = QColor ( 0x44, 0x44, 0x44 ); /* Gray */
|
||||
|
||||
// Available colors
|
||||
// XXX - Add custom
|
||||
const QList<QRgb> ColorUtils::graph_colors_ = QList<QRgb>()
|
||||
<< tango_aluminium_6 // Bar outline (use black instead)?
|
||||
<< tango_sky_blue_5
|
||||
<< tango_butter_6
|
||||
<< tango_chameleon_5
|
||||
<< tango_scarlet_red_5
|
||||
<< tango_plum_5
|
||||
<< tango_orange_6
|
||||
<< tango_aluminium_3
|
||||
<< tango_sky_blue_3
|
||||
<< tango_butter_3
|
||||
<< tango_chameleon_3
|
||||
<< tango_scarlet_red_3
|
||||
<< tango_plum_3
|
||||
<< tango_orange_3;
|
||||
|
||||
ColorUtils::ColorUtils(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
@ -109,6 +91,58 @@ QRgb ColorUtils::alphaBlend(const QBrush &brush1, const QBrush &brush2, qreal al
|
|||
return alphaBlend(brush1.color(), brush2.color(), alpha);
|
||||
}
|
||||
|
||||
QList<QRgb> ColorUtils::graph_colors_;
|
||||
const QList<QRgb> ColorUtils::graphColors()
|
||||
{
|
||||
if (graph_colors_.isEmpty()) {
|
||||
// Available graph colors
|
||||
// XXX - Add custom
|
||||
graph_colors_ = QList<QRgb>()
|
||||
<< tango_aluminium_6 // Bar outline (use black instead)?
|
||||
<< tango_sky_blue_5
|
||||
<< tango_butter_6
|
||||
<< tango_chameleon_5
|
||||
<< tango_scarlet_red_5
|
||||
<< tango_plum_5
|
||||
<< tango_orange_6
|
||||
<< tango_aluminium_3
|
||||
<< tango_sky_blue_3
|
||||
<< tango_butter_3
|
||||
<< tango_chameleon_3
|
||||
<< tango_scarlet_red_3
|
||||
<< tango_plum_3
|
||||
<< tango_orange_3;
|
||||
}
|
||||
return graph_colors_;
|
||||
}
|
||||
|
||||
QRgb ColorUtils::graphColor(int item)
|
||||
{
|
||||
if (graph_colors_.isEmpty()) graphColors(); // Init list.
|
||||
return graph_colors_[item % graph_colors_.size()];
|
||||
}
|
||||
|
||||
QList<QRgb> ColorUtils::sequence_colors_;
|
||||
QRgb ColorUtils::sequenceColor(int item)
|
||||
{
|
||||
if (sequence_colors_.isEmpty()) {
|
||||
// Available sequence colors. Copied from gtk/graph_analysis.c.
|
||||
// XXX - Add custom?
|
||||
sequence_colors_ = QList<QRgb>()
|
||||
<< qRgb(144, 238, 144)
|
||||
<< qRgb(255, 160, 123)
|
||||
<< qRgb(255, 182, 193)
|
||||
<< qRgb(250, 250, 210)
|
||||
<< qRgb(255, 255, 52)
|
||||
<< qRgb(103, 205, 170)
|
||||
<< qRgb(224, 255, 255)
|
||||
<< qRgb(176, 196, 222)
|
||||
<< qRgb(135, 206, 254)
|
||||
<< qRgb(211, 211, 211);
|
||||
}
|
||||
return sequence_colors_[item % sequence_colors_.size()];
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
|
|
|
@ -53,15 +53,17 @@ public:
|
|||
static const QColor expert_color_foreground; /* black */
|
||||
static const QColor hidden_proto_item; /* gray */
|
||||
|
||||
static const QList<QRgb> graphColors() { return graph_colors_; }
|
||||
static QRgb graphColor(int item) { return graph_colors_[item % graph_colors_.size()]; }
|
||||
static const QList<QRgb> graphColors();
|
||||
static QRgb graphColor(int item);
|
||||
static QRgb sequenceColor(int item);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
static const QList<QRgb> graph_colors_;
|
||||
static QList<QRgb> graph_colors_;
|
||||
static QList<QRgb> sequence_colors_;
|
||||
};
|
||||
|
||||
void color_filter_qt_add_cb(color_filter_t *colorf, gpointer user_data);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "ui/tap-sequence-analysis.h"
|
||||
|
||||
#include "color_utils.h"
|
||||
#include "qt_ui_utils.h"
|
||||
|
||||
#include <QFont>
|
||||
|
@ -187,7 +188,7 @@ void SequenceDiagram::draw(QCPPainter *painter)
|
|||
QPen fg_pen;
|
||||
qreal alpha = 0.50;
|
||||
|
||||
// Lifelines (node lines)
|
||||
// Lifelines (node lines). Will likely be overdrawn below.
|
||||
painter->save();
|
||||
painter->setOpacity(alpha);
|
||||
fg_pen = mainPen();
|
||||
|
@ -208,36 +209,41 @@ void SequenceDiagram::draw(QCPPainter *painter)
|
|||
double cur_key = it.key();
|
||||
seq_analysis_item_t *sai = it.value().value;
|
||||
QPen fg_pen(mainPen());
|
||||
QColor bg_color;
|
||||
|
||||
if (sai->frame_number == selected_packet_) {
|
||||
// Highlighted background
|
||||
painter->save();
|
||||
QRect bg_rect(
|
||||
QPoint(coordsToPixels(cur_key - 0.5, value_axis_->range().lower).toPoint()),
|
||||
QPoint(coordsToPixels(cur_key + 0.5, value_axis_->range().upper).toPoint()));
|
||||
QPalette sel_pal;
|
||||
painter->fillRect(bg_rect, sel_pal.brush(QPalette::Highlight));
|
||||
fg_pen.setColor(sel_pal.color(QPalette::HighlightedText));
|
||||
|
||||
// Highlighted lifelines
|
||||
painter->save();
|
||||
QPen hl_pen = fg_pen;
|
||||
hl_pen.setStyle(Qt::DashLine);
|
||||
painter->setPen(hl_pen);
|
||||
painter->setOpacity(alpha);
|
||||
for (int ll_x = value_axis_->range().lower; ll_x < value_axis_->range().upper; ll_x++) {
|
||||
// Only draw where we have arrows.
|
||||
if (ll_x < 0 || ll_x >= value_axis_->tickVector().size()) continue;
|
||||
QPoint ll_start(coordsToPixels(cur_key - 0.5, ll_x).toPoint());
|
||||
QPoint ll_end(coordsToPixels(cur_key + 0.5, ll_x).toPoint());
|
||||
hl_pen.setDashOffset(bg_rect.top() - ll_start.x());
|
||||
painter->drawLine(ll_start, ll_end);
|
||||
}
|
||||
painter->restore();
|
||||
|
||||
painter->restore();
|
||||
bg_color = sel_pal.color(QPalette::Highlight);
|
||||
} else {
|
||||
fg_pen.setColor(Qt::black);
|
||||
bg_color = ColorUtils::sequenceColor(sai->conv_num);
|
||||
}
|
||||
|
||||
// Highlighted background
|
||||
// painter->save();
|
||||
QRect bg_rect(
|
||||
QPoint(coordsToPixels(cur_key - 0.5, value_axis_->range().lower).toPoint()),
|
||||
QPoint(coordsToPixels(cur_key + 0.5, value_axis_->range().upper).toPoint()));
|
||||
painter->fillRect(bg_rect, bg_color);
|
||||
// painter->restore();
|
||||
|
||||
// Highlighted lifelines
|
||||
painter->save();
|
||||
QPen hl_pen = fg_pen;
|
||||
hl_pen.setStyle(Qt::DashLine);
|
||||
painter->setPen(hl_pen);
|
||||
painter->setOpacity(alpha);
|
||||
for (int ll_x = value_axis_->range().lower; ll_x < value_axis_->range().upper; ll_x++) {
|
||||
// Only draw where we have arrows.
|
||||
if (ll_x < 0 || ll_x >= value_axis_->tickVector().size()) continue;
|
||||
QPoint ll_start(coordsToPixels(cur_key - 0.5, ll_x).toPoint());
|
||||
QPoint ll_end(coordsToPixels(cur_key + 0.5, ll_x).toPoint());
|
||||
hl_pen.setDashOffset(bg_rect.top() - ll_start.x());
|
||||
painter->drawLine(ll_start, ll_end);
|
||||
}
|
||||
painter->restore();
|
||||
|
||||
if (cur_key < key_axis_->range().lower || cur_key > key_axis_->range().upper) {
|
||||
continue;
|
||||
}
|
||||
|
@ -283,14 +289,17 @@ void SequenceDiagram::draw(QCPPainter *painter)
|
|||
painter->drawText(text_pt, arrow_label);
|
||||
|
||||
if (sai->port_src && sai->port_dst) {
|
||||
QString port_num = QString::number(sai->port_src);
|
||||
text_pt = QPoint(arrow_start.x() - en_w - (cfm.width(port_num) * dir_mul),
|
||||
arrow_start.y() + (en_w / 2));
|
||||
painter->drawText(text_pt, port_num);
|
||||
int left_x = dir_mul > 0 ? arrow_start.x() : arrow_end.x();
|
||||
int right_x = dir_mul > 0 ? arrow_end.x() : arrow_start.x();
|
||||
QString port_left = QString::number(dir_mul > 0 ? sai->port_src : sai->port_dst);
|
||||
QString port_right = QString::number(dir_mul > 0 ? sai->port_dst : sai->port_src);
|
||||
|
||||
port_num = QString::number(sai->port_dst);
|
||||
text_pt.setX(arrow_end.x() - en_w + (cfm.width(port_num) * dir_mul));
|
||||
painter->drawText(text_pt, port_num);
|
||||
text_pt = QPoint(left_x - en_w - cfm.width(port_left),
|
||||
arrow_start.y() + (en_w / 2));
|
||||
painter->drawText(text_pt, port_left);
|
||||
|
||||
text_pt.setX(right_x + en_w);
|
||||
painter->drawText(text_pt, port_right);
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "wsutil/nstime.h"
|
||||
#include "wsutil/utf8_entities.h"
|
||||
|
||||
#include "color_utils.h"
|
||||
#include "progress_frame.h"
|
||||
#include "sequence_diagram.h"
|
||||
#include "wireshark_application.h"
|
||||
|
@ -37,6 +38,9 @@
|
|||
#include <QPoint>
|
||||
|
||||
// To do:
|
||||
// - Add zoom controls.
|
||||
// - Limit dragging to valid ranges.
|
||||
// - Handle trackpad and mouse wheel scrolling.
|
||||
// - Add UTF8 to text dump
|
||||
// - Save to XMI? http://www.umlgraph.org/
|
||||
// - Time: abs vs delta
|
||||
|
@ -46,8 +50,6 @@
|
|||
// - Change line_style to seq_type (i.e. draw ACKs dashed)
|
||||
// - Create WSGraph subclasses with common behavior.
|
||||
// - Help button and text
|
||||
// - Diagram shrinks when you click on it on retina displays.
|
||||
// - Add zoom controls.
|
||||
|
||||
SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *info) :
|
||||
WiresharkDialog(parent, cf),
|
||||
|
@ -55,7 +57,7 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i
|
|||
info_(info),
|
||||
num_items_(0),
|
||||
packet_num_(0),
|
||||
node_label_w_(20)
|
||||
sequence_w_(1)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
loadGeometry(parent.width(), parent.height() * 4 / 5);
|
||||
|
@ -80,9 +82,32 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i
|
|||
sp->xAxis->setPadding(0);
|
||||
sp->xAxis->setLabelPadding(0);
|
||||
sp->xAxis->setTickLabelPadding(0);
|
||||
|
||||
QPen base_pen(ColorUtils::alphaBlend(palette().text(), palette().base(), 0.25));
|
||||
base_pen.setWidthF(0.5);
|
||||
sp->xAxis2->setBasePen(base_pen);
|
||||
sp->yAxis->setBasePen(base_pen);
|
||||
sp->yAxis2->setBasePen(base_pen);
|
||||
|
||||
sp->xAxis2->setVisible(true);
|
||||
sp->yAxis2->setVisible(true);
|
||||
|
||||
key_text_ = new QCPItemText(sp);
|
||||
key_text_->setText(tr("Time"));
|
||||
sp->addItem(key_text_);
|
||||
|
||||
key_text_->setPositionAlignment(Qt::AlignRight | Qt::AlignBottom);
|
||||
key_text_->position->setType(QCPItemPosition::ptAbsolute);
|
||||
key_text_->setClipToAxisRect(false);
|
||||
|
||||
comment_text_ = new QCPItemText(sp);
|
||||
comment_text_->setText(tr("Comment"));
|
||||
sp->addItem(comment_text_);
|
||||
|
||||
comment_text_->setPositionAlignment(Qt::AlignLeft | Qt::AlignBottom);
|
||||
comment_text_->position->setType(QCPItemPosition::ptAbsolute);
|
||||
comment_text_->setClipToAxisRect(false);
|
||||
|
||||
one_em_ = QFontMetrics(sp->yAxis->labelFont()).height();
|
||||
ui->horizontalScrollBar->setSingleStep(100 / one_em_);
|
||||
ui->verticalScrollBar->setSingleStep(100 / one_em_);
|
||||
|
@ -134,8 +159,6 @@ SequenceDialog::SequenceDialog(QWidget &parent, CaptureFile &cf, SequenceInfo *i
|
|||
connect(this, SIGNAL(goToPacket(int)), seq_diagram_, SLOT(setSelectedPacket(int)));
|
||||
|
||||
disconnect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
|
||||
QTimer::singleShot(0, this, SLOT(fillDiagram()));
|
||||
}
|
||||
|
||||
SequenceDialog::~SequenceDialog()
|
||||
|
@ -151,7 +174,7 @@ void SequenceDialog::updateWidgets()
|
|||
|
||||
void SequenceDialog::showEvent(QShowEvent *)
|
||||
{
|
||||
resetAxes();
|
||||
QTimer::singleShot(0, this, SLOT(fillDiagram()));
|
||||
}
|
||||
|
||||
void SequenceDialog::resizeEvent(QResizeEvent *)
|
||||
|
@ -350,18 +373,8 @@ void SequenceDialog::fillDiagram()
|
|||
seq_diagram_->setData(info_->sainfo());
|
||||
}
|
||||
|
||||
QFontMetrics vfm = QFontMetrics(sp->xAxis2->labelFont());
|
||||
char* addr_str;
|
||||
node_label_w_ = 0;
|
||||
for (guint i = 0; i < info_->sainfo()->num_nodes; i++) {
|
||||
addr_str = address_to_display(NULL, &(info_->sainfo()->nodes[i]));
|
||||
int label_w = vfm.width(addr_str);
|
||||
if (node_label_w_ < label_w) {
|
||||
node_label_w_ = label_w;
|
||||
}
|
||||
wmem_free(NULL, addr_str);
|
||||
}
|
||||
node_label_w_ = (node_label_w_ * 3 / 4) + one_em_;
|
||||
QFontMetrics fm = QFontMetrics(sp->xAxis2->labelFont());
|
||||
sequence_w_ = fm.height() * 15 ; // Arbitrary
|
||||
|
||||
mouseMoved(NULL);
|
||||
resetAxes();
|
||||
|
@ -394,6 +407,7 @@ void SequenceDialog::resetAxes(bool keep_lower)
|
|||
if (!info_->sainfo()) return;
|
||||
|
||||
QCustomPlot *sp = ui->sequencePlot;
|
||||
|
||||
// Allow space for labels on the top and port numbers on the left.
|
||||
double top_pos = -1.0, left_pos = -0.5;
|
||||
if (keep_lower) {
|
||||
|
@ -401,21 +415,42 @@ void SequenceDialog::resetAxes(bool keep_lower)
|
|||
left_pos = sp->xAxis2->range().lower;
|
||||
}
|
||||
|
||||
double range_ratio = sp->xAxis2->axisRect()->width() / node_label_w_;
|
||||
sp->xAxis2->setRange(left_pos, range_ratio + left_pos);
|
||||
double range_span = sp->viewport().width() / sequence_w_;
|
||||
sp->xAxis2->setRange(left_pos, range_span + left_pos);
|
||||
|
||||
range_ratio = sp->yAxis->axisRect()->height() / (one_em_ * 1.5);
|
||||
sp->yAxis->setRange(top_pos, range_ratio + top_pos);
|
||||
range_span = sp->axisRect()->height() / (one_em_ * 1.5);
|
||||
sp->yAxis->setRange(top_pos, range_span + top_pos);
|
||||
|
||||
double rmin = sp->xAxis2->range().size() / 2;
|
||||
ui->horizontalScrollBar->setRange((rmin - 0.5) * 100, (info_->sainfo()->num_nodes - 0.5 - rmin) * 100);
|
||||
xAxisChanged(sp->xAxis2->range());
|
||||
ui->horizontalScrollBar->setValue(ui->horizontalScrollBar->minimum()); // Shouldn't be needed.
|
||||
|
||||
rmin = (sp->yAxis->range().size() / 2);
|
||||
ui->verticalScrollBar->setRange((rmin - 1.0) * 100, (num_items_ - 0.5 - rmin) * 100);
|
||||
yAxisChanged(sp->yAxis->range());
|
||||
|
||||
sp->replot();
|
||||
// It would be exceedingly handy if we could do one or both of the
|
||||
// following:
|
||||
// - Position an axis label above its axis inline with the tick labels.
|
||||
// - Anchor a QCPItemText to one of the corners of a QCPAxis.
|
||||
// Neither of those appear to be possible, so we first call replot in
|
||||
// order to lay out our X axes, place our labels, the call replot again.
|
||||
sp->replot(QCustomPlot::rpQueued);
|
||||
|
||||
QRect axis_rect = sp->axisRect()->rect();
|
||||
key_text_->position->setCoords(axis_rect.left()
|
||||
- sp->yAxis->padding()
|
||||
- sp->yAxis->tickLabelPadding()
|
||||
- sp->yAxis->offset(),
|
||||
axis_rect.top());
|
||||
comment_text_->position->setCoords(axis_rect.right()
|
||||
+ sp->yAxis2->padding()
|
||||
+ sp->yAxis2->tickLabelPadding()
|
||||
+ sp->yAxis2->offset(),
|
||||
axis_rect.top());
|
||||
|
||||
sp->replot(QCustomPlot::rpHint);
|
||||
}
|
||||
|
||||
void SequenceDialog::on_resetButton_clicked()
|
||||
|
|
|
@ -108,8 +108,10 @@ private:
|
|||
int num_items_;
|
||||
guint32 packet_num_;
|
||||
double one_em_;
|
||||
int node_label_w_;
|
||||
int sequence_w_;
|
||||
QMenu ctx_menu_;
|
||||
QCPItemText *key_text_;
|
||||
QCPItemText *comment_text_;
|
||||
|
||||
void panAxes(int x_pixels, int y_pixels);
|
||||
void resetAxes(bool keep_lower = false);
|
||||
|
|
Loading…
Reference in New Issue