aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2015-02-23 17:56:14 -0800
committerGerald Combs <gerald@wireshark.org>2015-03-05 16:45:04 +0000
commitf2b35a180f12575bcd4198add4a6478b4ce41802 (patch)
treea14fcab1ca616169b1649f8192250bf0f9925130
parenta065fefe689a1c839fc74e5b253212f0efddfced (diff)
Qt: Add extra related packet indicator types.
Add the ability to set frame number types: none, request, or response. Use the types to draw different related packet indicators in the packet list. Track the conversation in PacketListRecord. Use it to draw dashed lines for unrelated frames. Set frame number types for DNS and ICMP. Instead of drawing a transparent QImage, alpha blend our foreground color and draw directly in our painter. Blend more toward the foreground color. Add FRAMENUM_TYPE to checkAPIs. Change-Id: I2495945bb436413e05d6ec697184a0b4fd5ad214 Reviewed-on: https://code.wireshark.org/review/7436 Reviewed-by: Gerald Combs <gerald@wireshark.org>
-rw-r--r--epan/dissectors/packet-dns.c4
-rw-r--r--epan/dissectors/packet-icmp.c4
-rw-r--r--epan/ftypes/ftypes.h8
-rw-r--r--epan/proto.c7
-rw-r--r--epan/proto.h3
-rwxr-xr-xtools/checkAPIs.pl4
-rw-r--r--ui/qt/CMakeLists.txt2
-rw-r--r--ui/qt/packet_list.cpp13
-rw-r--r--ui/qt/packet_list.h1
-rw-r--r--ui/qt/packet_list_record.cpp8
-rw-r--r--ui/qt/packet_list_record.h6
-rw-r--r--ui/qt/proto_tree.cpp7
-rw-r--r--ui/qt/proto_tree.h4
-rw-r--r--ui/qt/related_packet_delegate.cpp158
-rw-r--r--ui/qt/related_packet_delegate.h22
15 files changed, 183 insertions, 68 deletions
diff --git a/epan/dissectors/packet-dns.c b/epan/dissectors/packet-dns.c
index 68c1d4ee59..b3789213f6 100644
--- a/epan/dissectors/packet-dns.c
+++ b/epan/dissectors/packet-dns.c
@@ -5177,12 +5177,12 @@ proto_register_dns(void)
{ &hf_dns_response_in,
{ "Response In", "dns.response_in",
- FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
"The response to this DNS query is in this frame", HFILL }},
{ &hf_dns_response_to,
{ "Request In", "dns.response_to",
- FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
"This is a response to the DNS query in this frame", HFILL }},
{ &hf_dns_time,
diff --git a/epan/dissectors/packet-icmp.c b/epan/dissectors/packet-icmp.c
index d58980db74..73c8a1c8f1 100644
--- a/epan/dissectors/packet-icmp.c
+++ b/epan/dissectors/packet-icmp.c
@@ -1872,7 +1872,7 @@ void proto_register_icmp(void)
{&hf_icmp_resp_in,
{"Response frame", "icmp.resp_in", FT_FRAMENUM, BASE_NONE,
- NULL, 0x0,
+ FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
"The frame number of the corresponding response",
HFILL}},
@@ -1884,7 +1884,7 @@ void proto_register_icmp(void)
{&hf_icmp_resp_to,
{"Request frame", "icmp.resp_to", FT_FRAMENUM, BASE_NONE,
- NULL, 0x0,
+ FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
"The frame number of the corresponding request", HFILL}},
{&hf_icmp_resptime,
diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h
index 71f6e9386c..226084449a 100644
--- a/epan/ftypes/ftypes.h
+++ b/epan/ftypes/ftypes.h
@@ -97,6 +97,14 @@ enum ftenum {
typedef enum ftenum ftenum_t;
+enum ft_framenum_type {
+ FT_FRAMENUM_NONE,
+ FT_FRAMENUM_REQUEST,
+ FT_FRAMENUM_RESPONSE
+};
+
+typedef enum ft_framenum_type ft_framenum_type_t;
+
struct _ftype_t;
typedef struct _ftype_t ftype_t;
diff --git a/epan/proto.c b/epan/proto.c
index 4c07a5e2c9..d22e41539a 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -5636,8 +5636,9 @@ tmp_fld_check_assert(header_field_info *hfinfo)
(hfinfo->type == FT_INT56) ||
(hfinfo->type == FT_INT64) ||
(hfinfo->type == FT_BOOLEAN) ||
- (hfinfo->type == FT_PROTOCOL) ))
- g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
+ (hfinfo->type == FT_PROTOCOL) ||
+ (hfinfo->type == FT_FRAMENUM) ))
+ g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
" (which is not allowed to have strings)\n",
hfinfo->name, hfinfo->abbrev, ftype_name(hfinfo->type));
@@ -6637,7 +6638,7 @@ fill_label_number(field_info *fi, gchar *label_str, gboolean is_signed)
fmtfunc(tmp, value);
label_fill(label_str, 0, hfinfo, tmp);
}
- else if (hfinfo->strings) {
+ else if (hfinfo->strings && hfinfo->type != FT_FRAMENUM) { /* Add fill_label_framenum? */
const char *val_str = hf_try_val_to_str_const(value, hfinfo, "Unknown");
out = hfinfo_number_vals_format(hfinfo, buf, value);
diff --git a/epan/proto.h b/epan/proto.h
index 5f47b53fb0..f62a1a904f 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -98,6 +98,9 @@ typedef void (*custom_fmt_func_64_t)(gchar *, guint64);
* header_field_info.strings */
#define RVALS(x) (const struct _range_string*)(x)
+/** Cast a ft_framenum_type_t, used to set header_field_info.strings */
+#define FRAMENUM_TYPE(x) GINT_TO_POINTER(x)
+
struct _protocol;
/** Structure for information about a protocol */
diff --git a/tools/checkAPIs.pl b/tools/checkAPIs.pl
index 679a364242..598e95a03b 100755
--- a/tools/checkAPIs.pl
+++ b/tools/checkAPIs.pl
@@ -1817,8 +1817,8 @@ sub check_hf_entries($$)
print STDERR "Error: $hf is passing the address of a pointer to RVALS in $filename\n";
$errorCount++;
}
- if ($convert !~ m/^((0[xX]0?)?0$|NULL$|VALS|VALS64|RVALS|TFS|CF_FUNC|&)/ && $display !~ /BASE_CUSTOM/) {
- print STDERR "Error: non-null $hf 'convert' field missing 'VALS|VALS64|RVALS|TFS|CF_FUNC|&' in $filename ?\n";
+ if ($convert !~ m/^((0[xX]0?)?0$|NULL$|VALS|VALS64|RVALS|TFS|CF_FUNC|FRAMENUM_TYPE|&)/ && $display !~ /BASE_CUSTOM/) {
+ print STDERR "Error: non-null $hf 'convert' field missing 'VALS|VALS64|RVALS|TFS|CF_FUNC|FRAMENUM_TYPE|&' in $filename ?\n";
$errorCount++;
}
## Benign...
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 9f6f7311eb..b1c56139bf 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -85,6 +85,7 @@ set(WIRESHARK_QT_HEADERS
protocol_hierarchy_dialog.h
qcustomplot.h
recent_file_status.h
+ related_packet_delegate.h
rtp_stream_dialog.h
sctp_all_assocs_dialog.h
sctp_assoc_analyse_dialog.h
@@ -119,7 +120,6 @@ endif()
file(GLOB EXTRA_QT_HEADERS
packet_list_record.h
qt_ui_utils.h
- related_packet_delegate.h
sparkline_delegate.h
stock_icon.h
)
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index 9f3dfcd971..fd3c509c6a 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -425,7 +425,8 @@ void PacketList::setProtoTree (ProtoTree *proto_tree) {
proto_tree_ = proto_tree;
connect(proto_tree_, SIGNAL(goToPacket(int)), this, SLOT(goToPacket(int)));
- connect(proto_tree_, SIGNAL(relatedFrame(int)), this, SLOT(addRelatedFrame(int)));
+ connect(proto_tree_, SIGNAL(relatedFrame(int,ft_framenum_type_t)),
+ &related_packet_delegate_, SLOT(addRelatedFrame(int,ft_framenum_type_t)));
}
void PacketList::setByteViewTab (ByteViewTab *byte_view_tab) {
@@ -456,12 +457,13 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS
if (!cap_file_->edt) return;
if (proto_tree_ && cap_file_->edt->tree) {
- proto_tree_->fillProtocolTree(cap_file_->edt->tree);
packet_info *pi = &cap_file_->edt->pi;
+ related_packet_delegate_.setCurrentFrame(pi->fd->num);
+ proto_tree_->fillProtocolTree(cap_file_->edt->tree);
conversation_t *conv = find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
pi->srcport, pi->destport, 0);
if (conv) {
- related_packet_delegate_.setConversationSpan(conv->setup_frame, conv->last_frame);
+ related_packet_delegate_.setConversation(conv);
}
viewport()->update();
}
@@ -1038,11 +1040,6 @@ void PacketList::unsetAllTimeReferences()
redrawVisiblePackets();
}
-void PacketList::addRelatedFrame(int related_frame)
-{
- related_packet_delegate_.addRelatedFrame(related_frame);
-}
-
void PacketList::showHeaderMenu(QPoint pos)
{
header_ctx_column_ = header()->logicalIndexAt(pos);
diff --git a/ui/qt/packet_list.h b/ui/qt/packet_list.h
index 357533c67b..8095fe7d2e 100644
--- a/ui/qt/packet_list.h
+++ b/ui/qt/packet_list.h
@@ -130,7 +130,6 @@ public slots:
void applyRecentColumnWidths();
private slots:
- void addRelatedFrame(int related_frame);
void showHeaderMenu(QPoint pos);
void headerMenuTriggered();
void columnVisibilityTriggered();
diff --git a/ui/qt/packet_list_record.cpp b/ui/qt/packet_list_record.cpp
index 8ded43bb1d..1bacfd66d9 100644
--- a/ui/qt/packet_list_record.cpp
+++ b/ui/qt/packet_list_record.cpp
@@ -26,6 +26,7 @@
#include <epan/epan_dissect.h>
#include <epan/column-info.h>
#include <epan/column.h>
+#include <epan/conversation.h>
#include "color.h"
#include "color_filters.h"
@@ -39,7 +40,8 @@ unsigned PacketListRecord::col_data_ver_ = 1;
PacketListRecord::PacketListRecord(frame_data *frameData) :
fdata_(frameData),
data_ver_(0),
- colorized_(false)
+ colorized_(false),
+ conv_(NULL)
{
}
@@ -159,6 +161,10 @@ void PacketListRecord::dissect(capture_file *cap_file, bool dissect_color)
}
data_ver_ = col_data_ver_;
+ packet_info *pi = &edt.pi;
+ conv_ = find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
+ pi->srcport, pi->destport, 0);
+
epan_dissect_cleanup(&edt);
ws_buffer_free(&buf);
}
diff --git a/ui/qt/packet_list_record.h b/ui/qt/packet_list_record.h
index af2b251eb4..8fea32a0de 100644
--- a/ui/qt/packet_list_record.h
+++ b/ui/qt/packet_list_record.h
@@ -35,6 +35,8 @@
#include <QList>
#include <QVariant>
+struct conversation;
+
class PacketListRecord
{
public:
@@ -44,6 +46,7 @@ public:
frame_data *frameData() const { return fdata_; }
// packet_list->col_to_text in gtk/packet_list_store.c
static int textColumn(int column) { return cinfo_column_.value(column, -1); }
+ struct conversation *conversation() { return conv_; }
int columnTextSize(const char *str);
static void resetColumns(column_info *cinfo);
@@ -63,6 +66,9 @@ private:
/** Has this record been colorized? */
bool colorized_;
+ /** Conversation. Used by RelatedPacketDelegate */
+ struct conversation *conv_;
+
void dissect(capture_file *cap_file, bool dissect_color = false);
void cacheColumnStrings(column_info *cinfo);
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index 992e78b5c5..c50a05fc93 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -107,7 +107,8 @@ proto_tree_draw_node(proto_node *node, gpointer data)
item->setData(0, Qt::FontRole, font);
if (fi->hfinfo->type == FT_FRAMENUM) {
- proto_tree->emitRelatedFrame(fi->value.value.uinteger);
+ ft_framenum_type_t framenum_type = (ft_framenum_type_t)GPOINTER_TO_INT(fi->hfinfo->strings);
+ proto_tree->emitRelatedFrame(fi->value.value.uinteger, framenum_type);
}
}
}
@@ -294,9 +295,9 @@ void ProtoTree::fillProtocolTree(proto_tree *protocol_tree) {
proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, invisibleRootItem());
}
-void ProtoTree::emitRelatedFrame(int related_frame)
+void ProtoTree::emitRelatedFrame(int related_frame, ft_framenum_type_t framenum_type)
{
- emit relatedFrame(related_frame);
+ emit relatedFrame(related_frame, framenum_type);
}
void ProtoTree::updateSelectionStatus(QTreeWidgetItem* item) {
diff --git a/ui/qt/proto_tree.h b/ui/qt/proto_tree.h
index e10fa67d8d..8890cca27a 100644
--- a/ui/qt/proto_tree.h
+++ b/ui/qt/proto_tree.h
@@ -37,7 +37,7 @@ class ProtoTree : public QTreeWidget
public:
explicit ProtoTree(QWidget *parent = 0);
void fillProtocolTree(proto_tree *protocol_tree);
- void emitRelatedFrame(int related_frame);
+ void emitRelatedFrame(int related_frame, ft_framenum_type_t framenum_type = FT_FRAMENUM_NONE);
void clear();
protected:
@@ -53,7 +53,7 @@ signals:
void protoItemSelected(field_info *);
void openPacketInNewWindow(bool);
void goToPacket(int);
- void relatedFrame(int);
+ void relatedFrame(int, ft_framenum_type_t);
public slots:
void setMonospaceFont(const QFont &mono_font);
diff --git a/ui/qt/related_packet_delegate.cpp b/ui/qt/related_packet_delegate.cpp
index c7964d2e8f..83c93ee491 100644
--- a/ui/qt/related_packet_delegate.cpp
+++ b/ui/qt/related_packet_delegate.cpp
@@ -22,22 +22,45 @@
#include "related_packet_delegate.h"
#include "packet_list_record.h"
-#include <QPainter>
+#include "color_utils.h"
+
#include <QApplication>
+#include <QPainter>
+
+// To do:
+// - Add other frame types and symbols (ACKs, etc).
+// - Add tooltips. It looks like this needs to be done in
+// PacketListModel::data.
+// - Add "Go -> Next Related" and "Go -> Previous Related"?
+// - Apply as filter?
+
+RelatedPacketDelegate::RelatedPacketDelegate(QWidget *parent) :
+ QStyledItemDelegate(parent),
+ conv_(NULL),
+ current_frame_(0)
+{
+ clear();
+}
void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
- int en_w = option.fontMetrics.height() / 2;
-
QStyleOptionViewItemV4 optv4 = option;
QStyledItemDelegate::initStyleOption(&optv4, index);
+ int em_w = optv4.fontMetrics.height();
+ int en_w = (em_w + 1) / 2;
optv4.features |= QStyleOptionViewItemV4::HasDecoration;
optv4.decorationSize.setHeight(1);
- optv4.decorationSize.setWidth(en_w);
+ optv4.decorationSize.setWidth(em_w);
QStyledItemDelegate::paint(painter, optv4, index);
+ guint32 setup_frame = 0, last_frame = 0;
+ if (conv_) {
+ setup_frame = (int) conv_->setup_frame;
+ last_frame = (int) conv_->last_frame;
+ }
+
const frame_data *fd;
PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
if (!record || (fd = record->frameData()) == NULL) {
@@ -62,41 +85,78 @@ void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem
} else {
fg = optv4.palette.color(cg, QPalette::Text);
}
- qreal alpha = 0.20; // Arbitrary. Should arguably be a preference.
- // We draw in the same place more than once so we first draw on a
- // QImage at 100% opacity then draw that on our packet list item.
- QImage overlay = QImage(en_w * 2, optv4.rect.height(), QImage::Format_ARGB32_Premultiplied);
- QPainter op(&overlay);
+ fg = ColorUtils::alphaBlend(fg, optv4.palette.color(cg, QPalette::Base), 0.5);
+ QPen line_pen(fg);
+ line_pen.setWidth(optv4.fontMetrics.lineWidth());
+ line_pen.setJoinStyle(Qt::RoundJoin);
+
+ painter->setPen(line_pen);
+ painter->translate(optv4.rect.x(), optv4.rect.y());
+ painter->translate(en_w + 0.5, 0.5);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ int height = optv4.rect.height();
- overlay.fill(Qt::transparent);
- op.setPen(fg);
- op.translate(en_w + 0.5, 0.5);
- op.setRenderHint(QPainter::Antialiasing, true);
+ // Uncomment to make the boundary visible.
+// painter->save();
+// painter->setPen(Qt::darkRed);
+// painter->drawRect(QRectF(0.5, 0.5, en_w - 1, height - 1));
+// painter->restore();
// The current decorations are based on what looked good and were easy
- // to code. W might want to improve them by drawing small dots or tick
- // marks for frames in the same conversation XOR draw a gap for unrelated
- // frames.
- if (first_frame_ > 0 && last_frame_ > 0 && first_frame_ != last_frame_) {
- int height = optv4.rect.height();
- if ((int) fd->num == first_frame_) {
- op.drawLine(0, height / 2, 0, height);
- op.drawLine(1, height / 2, en_w, height / 2);
- } else if ((int) fd->num > first_frame_ && (int) fd->num < last_frame_) {
- op.drawLine(0, 0, 0, height);
- } else if ((int) fd->num == last_frame_) {
- op.drawLine(0, 0, 0, height / 2);
- op.drawLine(1, height / 2, en_w, height / 2);
+ // to code.
+
+ // Vertical line. Lower and upper half for the start and end of the
+ // conversation respectively, solid for conversation member, dashed
+ // for other packets in the start-end range.
+ if (setup_frame > 0 && last_frame > 0 && setup_frame != last_frame) {
+ if (fd->num == setup_frame) {
+ painter->drawLine(0, height / 2, 0, height);
+ painter->drawLine(1, height / 2, en_w - 1, height / 2);
+ } else if (fd->num > setup_frame && fd->num < last_frame) {
+ painter->save();
+ if (conv_ != record->conversation()) {
+ QPen other_pen(line_pen);
+ other_pen.setStyle(Qt::DashLine);
+ painter->setPen(other_pen);
+ }
+ painter->drawLine(0, 0, 0, height);
+ painter->restore();
+ } else if (fd->num == last_frame) {
+ painter->drawLine(0, 0, 0, height / 2);
+ painter->drawLine(1, height / 2, en_w, height / 2);
}
}
+
+ // Related packet indicator. Rightward arrow for requests, leftward
+ // arrow for responses, circle for others.
if (related_frames_.contains(fd->num)) {
- op.setBrush(fg);
- op.drawEllipse(QPointF(0.0, optv4.rect.height() / 2), 2, 2);
+ painter->setBrush(fg);
+ switch (related_frames_[fd->num]) {
+ // Request and response arrows are moved forward one pixel in order to
+ // maximize white space between the heads and the conversation line.
+ case FT_FRAMENUM_REQUEST:
+ {
+ int hh = height / 2;
+ QPoint tail(2 - en_w, hh);
+ QPoint head(en_w, hh);
+ drawArrow(painter, tail, head, hh / 2);
+ break;
+ }
+ case FT_FRAMENUM_RESPONSE:
+ {
+ int hh = height / 2;
+ QPoint tail(en_w - 1, hh);
+ QPoint head(1 - en_w, hh);
+ drawArrow(painter, tail, head, hh / 2);
+ break;
+ }
+ case FT_FRAMENUM_NONE:
+ default:
+ painter->drawEllipse(QPointF(0.0, optv4.rect.height() / 2), 2, 2);
+ }
}
- painter->setOpacity(alpha);
- painter->drawImage(optv4.rect.x(), optv4.rect.y(), overlay);
painter->restore();
}
@@ -106,21 +166,47 @@ QSize RelatedPacketDelegate::sizeHint(const QStyleOptionViewItem &option,
QStyledItemDelegate::sizeHint(option, index).height());
}
+void RelatedPacketDelegate::drawArrow(QPainter *painter, QPoint tail, QPoint head, int head_size) const
+{
+ int x_mul = head.x() > tail.x() ? -1 : 1;
+ QPoint head_points[] = {
+ head,
+ QPoint(head.x() + (head_size * x_mul), head.y() + (head_size / 2)),
+ QPoint(head.x() + (head_size * x_mul), head.y() - (head_size / 2)),
+ };
+
+ painter->drawLine(tail.x(), tail.y(), head.x() + (head_size * x_mul), head.y());
+ painter->drawPolygon(head_points, 3);
+}
+
void RelatedPacketDelegate::clear()
{
related_frames_.clear();
- first_frame_ = last_frame_ = -1;
+ current_frame_ = 0;
+ conv_ = NULL;
}
-void RelatedPacketDelegate::addRelatedFrame(int frame_num)
+void RelatedPacketDelegate::addRelatedFrame(int frame_num, ft_framenum_type_t framenum_type)
{
- related_frames_ << frame_num;
+ related_frames_[frame_num] = framenum_type;
+ // Last match wins. Last match might not make sense, however.
+ if (current_frame_ > 0) {
+ switch (framenum_type) {
+ case FT_FRAMENUM_REQUEST:
+ related_frames_[current_frame_] = FT_FRAMENUM_RESPONSE;
+ break;
+ case FT_FRAMENUM_RESPONSE:
+ related_frames_[current_frame_] = FT_FRAMENUM_REQUEST;
+ break;
+ default:
+ break;
+ }
+ }
}
-void RelatedPacketDelegate::setConversationSpan(int first_frame, int last_frame)
+void RelatedPacketDelegate::setConversation(conversation *conv)
{
- first_frame_ = first_frame;
- last_frame_ = last_frame;
+ conv_ = conv;
}
/*
diff --git a/ui/qt/related_packet_delegate.h b/ui/qt/related_packet_delegate.h
index db8b1a617a..c33bbf2c72 100644
--- a/ui/qt/related_packet_delegate.h
+++ b/ui/qt/related_packet_delegate.h
@@ -26,16 +26,23 @@
#include "epan/conversation.h"
-#include <QList>
+#include <QHash>
#include <QStyledItemDelegate>
+class QPainter;
+struct conversation;
+
class RelatedPacketDelegate : public QStyledItemDelegate
{
+ Q_OBJECT
public:
- RelatedPacketDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) { clear(); }
+ RelatedPacketDelegate(QWidget *parent = 0);
void clear();
- void addRelatedFrame(int frame_num);
- void setConversationSpan(int first_frame, int last_frame);
+ void setCurrentFrame(guint32 current_frame) { current_frame_ = current_frame; }
+ void setConversation(struct conversation *conv);
+
+public slots:
+ void addRelatedFrame(int frame_num, ft_framenum_type_t framenum_type = FT_FRAMENUM_NONE);
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -44,10 +51,11 @@ protected:
const QModelIndex &index) const;
private:
- QList<int> related_frames_;
- int first_frame_;
- int last_frame_;
+ QHash<int, ft_framenum_type_t> related_frames_;
+ struct conversation *conv_;
+ guint32 current_frame_;
+ void drawArrow(QPainter *painter, QPoint tail, QPoint head, int head_size) const;
signals: