forked from osmocom/wireshark
Qt: ByteViewText hover information.
When the user hovers over a byte view field, highlight it and show a description in the status bar. Add a "byte" status bar context and fix a label stack pop bug. Keep proto_find_field_from_offset from matching generated items. Otherwise hovering and selecting finds things like GeoIP entries and checksum validation information. This affects the GTK+ UI as well. Change-Id: Ic81c0d8159510a72d30c41f961807d8a48d05e16 Reviewed-on: https://code.wireshark.org/review/4943 Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
parent
c33deaa92f
commit
1c159818fd
|
@ -6658,7 +6658,7 @@ check_for_offset(proto_node *node, const gpointer data)
|
|||
offset_search_t *offsearch = (offset_search_t *)data;
|
||||
|
||||
/* !fi == the top most container node which holds nothing */
|
||||
if (fi && !PROTO_ITEM_IS_HIDDEN(node) && fi->ds_tvb && offsearch->tvb == fi->ds_tvb) {
|
||||
if (fi && !PROTO_ITEM_IS_HIDDEN(node) && !PROTO_ITEM_IS_GENERATED(node) && fi->ds_tvb && offsearch->tvb == fi->ds_tvb) {
|
||||
if (offsearch->offset >= (guint) fi->start &&
|
||||
offsearch->offset < (guint) (fi->start + fi->length)) {
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ void ByteViewTab::addTab(const char *name, tvbuff_t *tvb, proto_tree *tree, QTre
|
|||
byte_view_text->setAccessibleName(name);
|
||||
byte_view_text->setMonospaceFont(mono_font_);
|
||||
connect(this, SIGNAL(monospaceFontChanged(QFont)), byte_view_text, SLOT(setMonospaceFont(QFont)));
|
||||
connect(byte_view_text, SIGNAL(byteFieldHovered(QString&)), this, SIGNAL(byteFieldHovered(QString&)));
|
||||
QTabWidget::addTab(byte_view_text, name);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ protected:
|
|||
|
||||
signals:
|
||||
void monospaceFontChanged(const QFont &mono_font);
|
||||
void byteFieldHovered(QString &);
|
||||
|
||||
public slots:
|
||||
void protoTreeItemChanged(QTreeWidgetItem *current);
|
||||
|
|
|
@ -48,17 +48,15 @@ ByteViewText::ByteViewText(QWidget *parent, tvbuff_t *tvb, proto_tree *tree, QTr
|
|||
bold_highlight_(false),
|
||||
encoding_(encoding),
|
||||
format_(BYTES_HEX),
|
||||
p_start_(-1),
|
||||
p_end_(-1),
|
||||
f_start_(0),
|
||||
f_end_(0),
|
||||
fa_start_(-1),
|
||||
fa_end_(-1),
|
||||
p_bound_(0, 0),
|
||||
f_bound_(0, 0),
|
||||
fa_bound_(0, 0),
|
||||
show_offset_(true),
|
||||
show_hex_(true),
|
||||
show_ascii_(true),
|
||||
row_width_(16)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ByteViewText::setEncoding(packet_char_enc encoding)
|
||||
|
@ -75,8 +73,8 @@ bool ByteViewText::hasDataSource(const tvbuff_t *ds_tvb) {
|
|||
|
||||
void ByteViewText::setProtocolHighlight(int start, int end)
|
||||
{
|
||||
p_start_ = qMax(0, start);
|
||||
p_end_ = qMax(0, end);
|
||||
p_bound_ = QPair<guint, guint>(qMax(0, start), qMax(0, end));
|
||||
p_bound_save_ = p_bound_;
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
|
@ -84,15 +82,15 @@ void ByteViewText::setFieldHighlight(int start, int end, guint32 mask, int mask_
|
|||
{
|
||||
Q_UNUSED(mask);
|
||||
Q_UNUSED(mask_le);
|
||||
f_start_ = qMax(0, start);
|
||||
f_end_ = qMax(0, end);
|
||||
f_bound_ = QPair<guint, guint>(qMax(0, start), qMax(0, end));
|
||||
f_bound_save_ = f_bound_;
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void ByteViewText::setFieldAppendixHighlight(int start, int end)
|
||||
{
|
||||
fa_start_ = qMax(0, start);
|
||||
fa_end_ = qMax(0, end);
|
||||
fa_bound_ = QPair<guint, guint>(qMax(0, start), qMax(0, end));
|
||||
fa_bound_save_ = f_bound_;
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
|
@ -176,25 +174,12 @@ void ByteViewText::resizeEvent(QResizeEvent *)
|
|||
}
|
||||
|
||||
void ByteViewText::mousePressEvent (QMouseEvent *event) {
|
||||
if (!tvb_ || event->button() != Qt::LeftButton ) {
|
||||
if (!tvb_ || !event || event->button() != Qt::LeftButton ) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint pt = event->pos();
|
||||
int byte = (verticalScrollBar()->value() + (pt.y() / line_spacing_)) * row_width_;
|
||||
int x = (horizontalScrollBar()->value() * font_width_) + pt.x();
|
||||
int col = x_pos_to_column_.value(x, -1);
|
||||
|
||||
if (col < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte += col;
|
||||
if ((guint) byte > tvb_captured_length(tvb_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
field_info *fi = proto_find_field_from_offset(proto_tree_, byte, tvb_);
|
||||
QPoint pos = event->pos();
|
||||
field_info *fi = fieldAtPixel(pos);
|
||||
|
||||
if (fi && tree_widget_) {
|
||||
// XXX - This should probably be a ProtoTree method.
|
||||
|
@ -209,6 +194,54 @@ void ByteViewText::mousePressEvent (QMouseEvent *event) {
|
|||
}
|
||||
}
|
||||
|
||||
void ByteViewText::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QString field_str;
|
||||
if (!event) {
|
||||
emit byteFieldHovered(field_str);
|
||||
p_bound_ = p_bound_save_;
|
||||
f_bound_ = f_bound_save_;
|
||||
fa_bound_ = fa_bound_save_;
|
||||
viewport()->update();
|
||||
return;
|
||||
}
|
||||
QPoint pos = event->pos();
|
||||
field_info *fi = fieldAtPixel(pos);
|
||||
if (fi) {
|
||||
if (fi->length < 2) {
|
||||
field_str = QString(tr("Byte %1"))
|
||||
.arg(fi->start);
|
||||
} else {
|
||||
field_str = QString(tr("Bytes %1-%2"))
|
||||
.arg(fi->start)
|
||||
.arg(fi->start + fi->length - 1);
|
||||
}
|
||||
field_str += QString(": %1 (%2)")
|
||||
.arg(fi->hfinfo->name)
|
||||
.arg(fi->hfinfo->abbrev);
|
||||
f_bound_ = QPair<guint, guint>(fi->start, fi->start + fi->length);
|
||||
p_bound_ = QPair<guint, guint>(0, 0);
|
||||
fa_bound_ = QPair<guint, guint>(0, 0);
|
||||
} else {
|
||||
p_bound_ = p_bound_save_;
|
||||
f_bound_ = f_bound_save_;
|
||||
fa_bound_ = fa_bound_save_;
|
||||
}
|
||||
emit byteFieldHovered(field_str);
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void ByteViewText::leaveEvent(QEvent *event)
|
||||
{
|
||||
QString empty;
|
||||
emit byteFieldHovered(empty);
|
||||
p_bound_ = p_bound_save_;
|
||||
f_bound_ = f_bound_save_;
|
||||
fa_bound_ = fa_bound_save_;
|
||||
viewport()->update();
|
||||
QAbstractScrollArea::leaveEvent(event);
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
const int ByteViewText::separator_interval_ = 8; // Insert a space after this many bytes
|
||||
|
@ -241,10 +274,10 @@ void ByteViewText::drawOffsetLine(QPainter &painter, const guint offset, const i
|
|||
highlight_state hex_state = StateNormal;
|
||||
bool add_space = tvb_pos != offset;
|
||||
|
||||
if ((tvb_pos >= f_start_ && tvb_pos < f_end_) || (tvb_pos >= fa_start_ && tvb_pos < fa_end_)) {
|
||||
if ((tvb_pos >= f_bound_.first && tvb_pos < f_bound_.second) || (tvb_pos >= fa_bound_.first && tvb_pos < fa_bound_.second)) {
|
||||
hex_state = StateField;
|
||||
offset_state = StateOffsetField;
|
||||
} else if (tvb_pos >= p_start_ && tvb_pos < p_end_) {
|
||||
} else if (tvb_pos >= p_bound_.first && tvb_pos < p_bound_.second) {
|
||||
hex_state = StateProtocol;
|
||||
}
|
||||
|
||||
|
@ -291,10 +324,10 @@ void ByteViewText::drawOffsetLine(QPainter &painter, const guint offset, const i
|
|||
highlight_state ascii_state = StateNormal;
|
||||
bool add_space = tvb_pos != offset;
|
||||
|
||||
if ((tvb_pos >= f_start_ && tvb_pos < f_end_) || (tvb_pos >= fa_start_ && tvb_pos < fa_end_)) {
|
||||
if ((tvb_pos >= f_bound_.first && tvb_pos < f_bound_.second) || (tvb_pos >= fa_bound_.first && tvb_pos < fa_bound_.second)) {
|
||||
ascii_state = StateField;
|
||||
offset_state = StateOffsetField;
|
||||
} else if (tvb_pos >= p_start_ && tvb_pos < p_end_) {
|
||||
} else if (tvb_pos >= p_bound_.first && tvb_pos < p_bound_.second) {
|
||||
ascii_state = StateProtocol;
|
||||
}
|
||||
|
||||
|
@ -433,6 +466,24 @@ void ByteViewText::updateScrollbars()
|
|||
horizontalScrollBar()->setRange(0, qMax(0, static_cast<int>((totalPixels() - viewport()->width()) / font_width_)));
|
||||
}
|
||||
|
||||
field_info *ByteViewText::fieldAtPixel(QPoint &pos)
|
||||
{
|
||||
int byte = (verticalScrollBar()->value() + (pos.y() / line_spacing_)) * row_width_;
|
||||
int x = (horizontalScrollBar()->value() * font_width_) + pos.x();
|
||||
int col = x_pos_to_column_.value(x, -1);
|
||||
|
||||
if (col < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
byte += col;
|
||||
if ((guint) byte > tvb_captured_length(tvb_)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return proto_find_field_from_offset(proto_tree_, byte, tvb_);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
|
|
|
@ -53,14 +53,18 @@ public:
|
|||
void setFieldHighlight(int start, int end, guint32 mask = 0, int mask_le = 0);
|
||||
void setFieldAppendixHighlight(int start, int end);
|
||||
|
||||
signals:
|
||||
void byteFieldHovered(QString &);
|
||||
|
||||
public slots:
|
||||
void setMonospaceFont(const QFont &mono_font);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *);
|
||||
virtual void resizeEvent(QResizeEvent *);
|
||||
void mousePressEvent (QMouseEvent * event);
|
||||
|
||||
virtual void mousePressEvent (QMouseEvent * event);
|
||||
virtual void mouseMoveEvent (QMouseEvent * event);
|
||||
virtual void leaveEvent(QEvent *event);
|
||||
|
||||
private:
|
||||
typedef enum {
|
||||
|
@ -80,6 +84,7 @@ private:
|
|||
int asciiPixels();
|
||||
int totalPixels();
|
||||
void updateScrollbars();
|
||||
field_info *fieldAtPixel(QPoint &pos);
|
||||
|
||||
static const int separator_interval_;
|
||||
tvbuff_t *tvb_;
|
||||
|
@ -94,14 +99,17 @@ private:
|
|||
|
||||
gboolean bold_highlight_;
|
||||
|
||||
/* data */
|
||||
// Data
|
||||
packet_char_enc encoding_; // ASCII or EBCDIC
|
||||
bytes_view_type format_; // bytes in hex or bytes as bits
|
||||
|
||||
/* data-highlight */
|
||||
guint p_start_, p_end_; // Protocol
|
||||
guint f_start_, f_end_; // Field
|
||||
guint fa_start_, fa_end_; // Field appendix
|
||||
// Data highlight
|
||||
QPair<guint,guint> p_bound_;
|
||||
QPair<guint,guint> f_bound_;
|
||||
QPair<guint,guint> fa_bound_;
|
||||
QPair<guint,guint> p_bound_save_;
|
||||
QPair<guint,guint> f_bound_save_;
|
||||
QPair<guint,guint> fa_bound_save_;
|
||||
|
||||
bool show_offset_; // Should we show the byte offset?
|
||||
bool show_hex_; // Should we show the hex display?
|
||||
|
|
|
@ -48,7 +48,7 @@ void LabelStack::setTemporaryContext(const int ctx) {
|
|||
}
|
||||
|
||||
void LabelStack::fillLabel() {
|
||||
StackItem *si;
|
||||
StackItem si;
|
||||
QString style_sheet;
|
||||
|
||||
style_sheet =
|
||||
|
@ -62,7 +62,7 @@ void LabelStack::fillLabel() {
|
|||
|
||||
si = labels_.first();
|
||||
|
||||
if (si->ctx == temporary_ctx_) {
|
||||
if (si.ctx == temporary_ctx_) {
|
||||
style_sheet += QString(
|
||||
" border-radius: 0.25em;"
|
||||
" color: #%1;"
|
||||
|
@ -74,23 +74,23 @@ void LabelStack::fillLabel() {
|
|||
|
||||
style_sheet += "}";
|
||||
setStyleSheet(style_sheet);
|
||||
setText(si->text);
|
||||
setText(si.text);
|
||||
}
|
||||
|
||||
void LabelStack::pushText(QString &text, int ctx) {
|
||||
StackItem *si = new StackItem;
|
||||
popText(ctx);
|
||||
|
||||
if (ctx == temporary_ctx_) {
|
||||
temporary_timer_.stop();
|
||||
popText(temporary_ctx_);
|
||||
|
||||
temporary_epoch_.start();
|
||||
temporary_timer_.start(temporary_flash_timeout_);
|
||||
emit toggleTemporaryFlash(true);
|
||||
}
|
||||
|
||||
si->text = text;
|
||||
si->ctx = ctx;
|
||||
StackItem si;
|
||||
si.text = text;
|
||||
si.ctx = ctx;
|
||||
labels_.prepend(si);
|
||||
fillLabel();
|
||||
}
|
||||
|
@ -122,10 +122,10 @@ void LabelStack::contextMenuEvent(QContextMenuEvent *event)
|
|||
}
|
||||
|
||||
void LabelStack::popText(int ctx) {
|
||||
QMutableListIterator<StackItem *> iter(labels_);
|
||||
QMutableListIterator<StackItem> iter(labels_);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
if (iter.next()->ctx == ctx) {
|
||||
if (iter.next().ctx == ctx) {
|
||||
iter.remove();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ private:
|
|||
} StackItem;
|
||||
|
||||
int temporary_ctx_;
|
||||
QList<StackItem *> labels_;
|
||||
QList<StackItem> labels_;
|
||||
QTime temporary_epoch_;
|
||||
QTimer temporary_timer_;
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ enum StatusContext {
|
|||
STATUS_CTX_MAIN,
|
||||
STATUS_CTX_FILE,
|
||||
STATUS_CTX_FIELD,
|
||||
STATUS_CTX_BYTE,
|
||||
STATUS_CTX_FILTER,
|
||||
STATUS_CTX_TEMPORARY
|
||||
};
|
||||
|
@ -251,6 +252,20 @@ void MainStatusBar::popFieldStatus() {
|
|||
info_status_.popText(STATUS_CTX_FIELD);
|
||||
}
|
||||
|
||||
void MainStatusBar::pushByteStatus(QString &message)
|
||||
{
|
||||
if (message.isNull()) {
|
||||
popByteStatus();
|
||||
} else {
|
||||
info_status_.pushText(message, STATUS_CTX_BYTE);
|
||||
}
|
||||
}
|
||||
|
||||
void MainStatusBar::popByteStatus()
|
||||
{
|
||||
info_status_.popText(STATUS_CTX_BYTE);
|
||||
}
|
||||
|
||||
void MainStatusBar::pushFilterStatus(QString &message) {
|
||||
info_status_.pushText(message, STATUS_CTX_FILTER);
|
||||
expertUpdate();
|
||||
|
|
|
@ -63,6 +63,8 @@ public slots:
|
|||
void popFileStatus();
|
||||
void pushFieldStatus(QString &message);
|
||||
void popFieldStatus();
|
||||
void pushByteStatus(QString &message);
|
||||
void popByteStatus();
|
||||
void pushFilterStatus(QString &message);
|
||||
void popFilterStatus();
|
||||
void pushProfileName();
|
||||
|
|
|
@ -359,10 +359,12 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
connect(proto_tree_, SIGNAL(protoItemSelected(QString&)),
|
||||
main_ui_->statusBar, SLOT(pushFieldStatus(QString&)));
|
||||
|
||||
connect(proto_tree_, SIGNAL(protoItemSelected(field_info *)),
|
||||
this, SLOT(setMenusForSelectedTreeRow(field_info *)));
|
||||
|
||||
connect(byte_view_tab_, SIGNAL(byteFieldHovered(QString&)),
|
||||
main_ui_->statusBar, SLOT(pushByteStatus(QString&)));
|
||||
|
||||
connect(&file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString&)),
|
||||
this, SLOT(openCaptureFile(QString&)));
|
||||
|
||||
|
|
Loading…
Reference in New Issue