wireshark/ui/qt/packet_list_record.cpp
Gerald Combs 5ab8490088 Qt: Allow multiple lines in the packet list.
Remove the setUniformRowHeights(true) call in the PacketList
constructor. This means that the packet list now calculates its height
by querying the Qt::SizeHintRole for every item instead of simply
multiplying item_height * number_of_rows.

Implement SizeHintRole in PacketListModel::data so that size
calculations aren't unbearably slow. We don't have any row text until an
item is drawn (via DisplayRole), so items with multiple lines end up
being rendered twice. Note where we make assumptions on line heights.

Although we call gtk_tree_view_set_fixed_height_mode() in the GTK+ UI we
don't have this problem there. GTK+ is apparently less strict about
enforcing row heights.

Bug: 10924
Change-Id: I98e9f4f5f321c2e03f18498e0a7e7556f88792a1
Reviewed-on: https://code.wireshark.org/review/7430
Petri-Dish: Evan Huus <eapache@gmail.com>
Reviewed-by: Evan Huus <eapache@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michal Labedzki <michal.labedzki@tieto.com>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
2015-03-12 16:29:58 +00:00

281 lines
8.4 KiB
C++

/* packet_list_record.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "packet_list_record.h"
#include <file.h>
#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"
#include "frame_tvbuff.h"
#include <QStringList>
QMap<int, int> PacketListRecord::cinfo_column_;
unsigned PacketListRecord::col_data_ver_ = 1;
PacketListRecord::PacketListRecord(frame_data *frameData) :
fdata_(frameData),
lines_(1),
line_count_changed_(false),
data_ver_(0),
colorized_(false),
conv_(NULL)
{
}
const QVariant PacketListRecord::columnString(capture_file *cap_file, int column)
{
// packet_list_store.c:packet_list_get_value
g_assert(fdata_);
if (!cap_file || column < 0 || column > cap_file->cinfo.num_cols) {
return QVariant();
}
if (column >= col_text_.size() || col_text_[column].isNull() || data_ver_ != col_data_ver_ || !colorized_) {
dissect(cap_file, !colorized_);
}
return col_text_.value(column, QByteArray());
}
void PacketListRecord::resetColumns(column_info *cinfo)
{
col_data_ver_++;
if (!cinfo) {
return;
}
cinfo_column_.clear();
int i, j;
for (i = 0, j = 0; i < cinfo->num_cols; i++) {
if (!col_based_on_frame_data(cinfo, i)) {
cinfo_column_[i] = j;
j++;
}
}
}
void PacketListRecord::resetColorized()
{
colorized_ = false;
}
void PacketListRecord::dissect(capture_file *cap_file, bool dissect_color)
{
// packet_list_store.c:packet_list_dissect_and_cache_record
epan_dissect_t edt;
column_info *cinfo = NULL;
gboolean create_proto_tree;
struct wtap_pkthdr phdr; /* Packet header */
Buffer buf; /* Packet data */
gboolean dissect_columns = col_text_.isEmpty() || data_ver_ != col_data_ver_;
if (!cap_file) {
return;
}
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
if (dissect_columns) {
cinfo = &cap_file->cinfo;
}
ws_buffer_init(&buf, 1500);
if (!cf_read_record_r(cap_file, fdata_, &phdr, &buf)) {
/*
* Error reading the record.
*
* Don't set the color filter for now (we might want
* to colorize it in some fashion to warn that the
* row couldn't be filled in or colorized), and
* set the columns to placeholder values, except
* for the Info column, where we'll put in an
* error message.
*/
if (dissect_columns) {
col_fill_in_error(cinfo, fdata_, FALSE, FALSE /* fill_fd_columns */);
cacheColumnStrings(cinfo);
}
if (dissect_color) {
fdata_->color_filter = NULL;
colorized_ = true;
}
ws_buffer_free(&buf);
return; /* error reading the record */
}
create_proto_tree = (dissect_color && color_filters_used()) ||
(dissect_columns && have_custom_cols(cinfo));
epan_dissect_init(&edt, cap_file->epan,
create_proto_tree,
FALSE /* proto_tree_visible */);
if (dissect_color)
color_filters_prime_edt(&edt);
if (dissect_columns)
col_custom_prime_edt(&edt, cinfo);
/*
* XXX - need to catch an OutOfMemoryError exception and
* attempt to recover from it.
*/
epan_dissect_run(&edt, cap_file->cd_t, &phdr, frame_tvbuff_new_buffer(fdata_, &buf), fdata_, cinfo);
if (dissect_color)
fdata_->color_filter = color_filters_colorize_packet(&edt);
if (dissect_columns) {
/* "Stringify" non frame_data vals */
epan_dissect_fill_in_columns(&edt, FALSE, FALSE /* fill_fd_columns */);
cacheColumnStrings(cinfo);
}
if (dissect_color) {
colorized_ = true;
}
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);
}
//#define MINIMIZE_STRING_COPYING 1
void PacketListRecord::cacheColumnStrings(column_info *cinfo)
{
// packet_list_store.c:packet_list_change_record(PacketList *packet_list, PacketListRecord *record, gint col, column_info *cinfo)
if (!cinfo) {
return;
}
col_text_.clear();
lines_ = 1;
line_count_changed_ = false;
for (int column = 0; column < cinfo->num_cols; ++column) {
int col_lines = 1;
#ifdef MINIMIZE_STRING_COPYING
int text_col = cinfo_column_.value(column, -1);
/* Column based on frame_data or it already contains a value */
if (text_col < 0) {
col_fill_in_frame_data(fdata_, cinfo, column, FALSE);
col_text_.append(cinfo->col_data[column]);
continue;
}
switch (cinfo->col_fmt[column]) {
case COL_DEF_SRC:
case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */
case COL_UNRES_SRC:
case COL_DEF_DL_SRC:
case COL_RES_DL_SRC:
case COL_UNRES_DL_SRC:
case COL_DEF_NET_SRC:
case COL_RES_NET_SRC:
case COL_UNRES_NET_SRC:
case COL_DEF_DST:
case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */
case COL_UNRES_DST:
case COL_DEF_DL_DST:
case COL_RES_DL_DST:
case COL_UNRES_DL_DST:
case COL_DEF_NET_DST:
case COL_RES_NET_DST:
case COL_UNRES_NET_DST:
case COL_PROTOCOL:
case COL_INFO:
case COL_IF_DIR:
case COL_DCE_CALL:
case COL_8021Q_VLAN_ID:
case COL_EXPERT:
case COL_FREQ_CHAN:
if (cinfo->col_data[column] && cinfo->col_data[column] != cinfo->col_buf[column]) {
/* This is a constant string, so we don't have to copy it */
// XXX - ui/gtk/packet_list_store.c uses G_MAXUSHORT. We don't do proper UTF8
// truncation in either case.
int col_text_len = MIN(qstrlen(cinfo->col_data[column]) + 1, COL_MAX_INFO_LEN);
col_text_.append(QByteArray::fromRawData(cinfo->col_data[column], col_text_len));
break;
}
/* !! FALL-THROUGH!! */
default:
if (!get_column_resolved(column) && cinfo->col_expr.col_expr_val[column]) {
/* Use the unresolved value in col_expr_val */
// XXX Use QContiguousCache?
col_text_.append(cinfo->col_expr.col_expr_val[column]);
} else {
col_text_.append(cinfo->col_data[column]);
}
break;
}
#else // MINIMIZE_STRING_COPYING
// XXX Use QContiguousCache?
QByteArray col_text;
if (!get_column_resolved(column) && cinfo->col_expr.col_expr_val[column]) {
/* Use the unresolved value in col_expr_val */
col_text = cinfo->col_expr.col_expr_val[column];
} else {
int text_col = cinfo_column_.value(column, -1);
if (text_col < 0) {
col_fill_in_frame_data(fdata_, cinfo, column, FALSE);
}
col_text = cinfo->col_data[column];
}
col_text_.append(col_text);
col_lines += col_text.count('\n');
if (col_lines > lines_) {
lines_ = col_lines;
line_count_changed_ = true;
}
#endif // MINIMIZE_STRING_COPYING
}
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/