Qt: Packet list column sorting.

Sorting behavior should be identical to GTK+.

Pass the correct position to beginInsertRows. Add a list of to-do items
to packet_list.cpp.

Change-Id: Ie6ab4b9f2d780a2af430d0f90529edca5485dada
Reviewed-on: https://code.wireshark.org/review/4481
Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
Gerald Combs 2014-10-05 12:23:33 -07:00 committed by Gerald Combs
parent 5051ae1cbe
commit 798eb97053
9 changed files with 144 additions and 24 deletions

View File

@ -23,6 +23,10 @@
#ifndef __FRAME_DATA_H__
#define __FRAME_DATA_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <epan/tvbuff.h>
#include <wsutil/nstime.h>
#include "ws_symbol_export.h"
@ -119,6 +123,10 @@ WS_DLL_PUBLIC void frame_data_set_after_dissect(frame_data *fdata,
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __FRAME_DATA__ */
/*

View File

@ -1578,7 +1578,7 @@ void MainWindow::setMenusForCaptureInProgress(bool capture_in_progress) {
main_ui_->actionSummary->setEnabled(capture_in_progress);
qDebug() << "FIX: packet list heading menu sensitivity";
// XXX Fix packet list heading menu sensitivity
// set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending",
// !capture_in_progress);
// set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending",

View File

@ -47,12 +47,17 @@
#include "frame_tvbuff.h"
#include <QTreeWidget>
#include <QContextMenuEvent>
#include <QHeaderView>
#include <QMessageBox>
#include <QScrollBar>
#include <QTabWidget>
#include <QTextEdit>
#include <QScrollBar>
#include <QContextMenuEvent>
#include <QMessageBox>
#include <QTreeWidget>
// To do:
// - Heading context menus
// - Catch column reordering and rebuild the column list accoringly.
// If we ever add the ability to open multiple capture files we might be
// able to use something like QMap<capture_file *, PacketList *> to match
@ -231,15 +236,16 @@ PacketList::PacketList(QWidget *parent) :
{
QMenu *submenu, *subsubmenu;
setItemsExpandable(FALSE);
setRootIsDecorated(FALSE);
setSortingEnabled(TRUE);
setUniformRowHeights(TRUE);
setItemsExpandable(false);
setRootIsDecorated(false);
setSortingEnabled(true);
setUniformRowHeights(true);
setAccessibleName("Packet list");
setItemDelegateForColumn(0, &related_packet_delegate_);
packet_list_model_ = new PacketListModel(this, cap_file_);
setModel(packet_list_model_);
sortByColumn(-1, Qt::AscendingOrder);
// XXX We might want to reimplement setParent() and fill in the context
// menu there.
@ -387,6 +393,7 @@ PacketList::PacketList(QWidget *parent) :
g_assert(gbl_cur_packet_list == NULL);
gbl_cur_packet_list = this;
connect(packet_list_model_, SIGNAL(goToPacket(int)), this, SLOT(goToPacket(int)));
connect(wsApp, SIGNAL(addressResolutionChanged()), this, SLOT(updateAll()));
}
@ -615,7 +622,7 @@ void PacketList::clear() {
/* XXX is this correct in all cases?
* Reset the sort column, use packetlist as model in case the list is frozen.
*/
sortByColumn(0, Qt::AscendingOrder);
sortByColumn(-1, Qt::AscendingOrder);
setColumnVisibility();
}
@ -718,7 +725,7 @@ QString &PacketList::getFilterFromRowAndColumn()
QString PacketList::packetComment()
{
int row = currentIndex().row();
frame_data *fdata;
const frame_data *fdata;
char *pkt_comment;
if (!cap_file_ || !packet_list_model_) return NULL;

View File

@ -76,7 +76,7 @@ int PacketListModel::packetNumberToRow(int packet_num) const
guint PacketListModel::recreateVisibleRows()
{
int pos = visible_rows_.count() + 1;
int pos = visible_rows_.count();
PacketListRecord *record;
beginResetModel();
@ -135,6 +135,103 @@ void PacketListModel::setMonospaceFont(const QFont &mono_font)
recreateVisibleRows();
}
// The Qt MVC documentation suggests using QSortFilterProxyModel for sorting
// and filtering. That seems like overkill but it might be something we want
// to do in the future.
int PacketListModel::sort_column_;
int PacketListModel::text_sort_column_;
Qt::SortOrder PacketListModel::sort_order_;
capture_file *PacketListModel::sort_cap_file_;
void PacketListModel::sort(int column, Qt::SortOrder order)
{
if (!cap_file_ || visible_rows_.length() < 1) {
return;
}
sort_column_ = column;
text_sort_column_ = PacketListRecord::textColumn(column);
sort_order_ = order;
sort_cap_file_ = cap_file_;
beginResetModel();
qSort(visible_rows_.begin(), visible_rows_.end(), recordLessThan);
for (int i = 0; i < visible_rows_.count(); i++) {
number_to_row_[visible_rows_[i]->frameData()->num] = i;
}
endResetModel();
if (cap_file_->current_frame) {
emit goToPacket(cap_file_->current_frame->num);
}
}
bool PacketListModel::recordLessThan(PacketListRecord *r1, PacketListRecord *r2)
{
int cmp_val = 0;
// Wherein we try to cram the logic of packet_list_compare_records,
// _packet_list_compare_records, and packet_list_compare_custom from
// gtk/packet_list_store.c into one function
if (sort_column_ < 0) {
// No column.
cmp_val = frame_data_compare(sort_cap_file_->epan, r1->frameData(), r2->frameData(), COL_NUMBER);
} else if (text_sort_column_ < 0) {
// Column comes directly from frame data
cmp_val = frame_data_compare(sort_cap_file_->epan, r1->frameData(), r2->frameData(), sort_cap_file_->cinfo.col_fmt[sort_column_]);
} else {
if (r1->columnString(sort_cap_file_, sort_column_).toByteArray().data() == r2->columnString(sort_cap_file_, sort_column_).toByteArray().data()) {
cmp_val = 0;
} else if (sort_cap_file_->cinfo.col_fmt[sort_column_] == COL_CUSTOM) {
header_field_info *hfi;
// Column comes from custom data
hfi = proto_registrar_get_byname(sort_cap_file_->cinfo.col_custom_field[sort_column_]);
if (hfi == NULL) {
cmp_val = frame_data_compare(sort_cap_file_->epan, r1->frameData(), r2->frameData(), COL_NUMBER);
} else if ((hfi->strings == NULL) &&
(((IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type)) &&
((hfi->display == BASE_DEC) || (hfi->display == BASE_DEC_HEX) ||
(hfi->display == BASE_OCT))) ||
(hfi->type == FT_DOUBLE) || (hfi->type == FT_FLOAT) ||
(hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
(hfi->type == FT_RELATIVE_TIME)))
{
/* Attempt to convert to numbers */
bool ok_r1, ok_r2;
double num_r1 = r1->columnString(sort_cap_file_, sort_column_).toDouble(&ok_r1);
double num_r2 = r2->columnString(sort_cap_file_, sort_column_).toDouble(&ok_r2);
if (!ok_r1 && !ok_r2) {
cmp_val = 0;
} else if (!ok_r1 || num_r1 < num_r2) {
cmp_val = -1;
} else if (!ok_r2 || num_r1 > num_r2) {
cmp_val = 1;
}
} else {
cmp_val = strcmp(r1->columnString(sort_cap_file_, sort_column_).toByteArray().data(), r2->columnString(sort_cap_file_, sort_column_).toByteArray().data());
}
} else {
cmp_val = strcmp(r1->columnString(sort_cap_file_, sort_column_).toByteArray().data(), r2->columnString(sort_cap_file_, sort_column_).toByteArray().data());
}
if (cmp_val == 0) {
// Last resort. Compare column numbers.
cmp_val = frame_data_compare(sort_cap_file_->epan, r1->frameData(), r2->frameData(), COL_NUMBER);
}
}
if (sort_order_ == Qt::AscendingOrder) {
return cmp_val < 0;
} else {
return cmp_val > 0;
}
}
int PacketListModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() >= prefs.num_cols)
@ -158,7 +255,7 @@ QVariant PacketListModel::data(const QModelIndex &index, int role) const
PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
if (!record)
return QVariant();
frame_data *fdata = record->frameData();
const frame_data *fdata = record->frameData();
if (!fdata)
return QVariant();
@ -242,7 +339,7 @@ QVariant PacketListModel::headerData(int section, Qt::Orientation orientation,
gint PacketListModel::appendPacket(frame_data *fdata)
{
PacketListRecord *record = new PacketListRecord(fdata);
gint pos = visible_rows_.count() + 1;
gint pos = visible_rows_.count();
physical_rows_ << record;

View File

@ -65,9 +65,11 @@ public:
int columnTextSize(const char *str);
signals:
void goToPacket(int);
public slots:
void setMonospaceFont(const QFont &mono_font);
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
private:
capture_file *cap_file_;
@ -78,6 +80,12 @@ private:
QMap<int, int> number_to_row_;
int header_height_;
static int sort_column_;
static int text_sort_column_;
static Qt::SortOrder sort_order_;
static capture_file *sort_cap_file_;
static bool recordLessThan(PacketListRecord *r1, PacketListRecord *r2);
};
#endif // PACKET_LIST_MODEL_H

View File

@ -33,7 +33,7 @@
#include <QStringList>
QMap<int, int> cinfo_column_;
QMap<int, int> PacketListRecord::cinfo_column_;
PacketListRecord::PacketListRecord(frame_data *frameData) :
fdata_(frameData),
@ -42,7 +42,7 @@ PacketListRecord::PacketListRecord(frame_data *frameData) :
{
}
QVariant PacketListRecord::columnString(capture_file *cap_file, int column)
const QVariant PacketListRecord::columnString(capture_file *cap_file, int column)
{
// packet_list_store.c:packet_list_get_value
g_assert(fdata_);
@ -58,10 +58,6 @@ QVariant PacketListRecord::columnString(capture_file *cap_file, int column)
return col_text_.value(column, QByteArray());
}
frame_data *PacketListRecord::frameData() {
return fdata_;
}
void PacketListRecord::resetColumns(column_info *cinfo)
{
if (!cinfo) {

View File

@ -40,8 +40,10 @@ class PacketListRecord
public:
PacketListRecord(frame_data *frameData);
// Return the string value for a column. Data is cached if possible.
QVariant columnString(capture_file *cap_file, int column);
frame_data *frameData();
const QVariant columnString(capture_file *cap_file, int column);
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); }
int columnTextSize(const char *str);
static void resetColumns(column_info *cinfo);
@ -52,6 +54,8 @@ private:
QList<QByteArray> col_text_;
frame_data *fdata_;
static QMap<int, int> cinfo_column_;
/** Has this record been columnized? */
// gboolean columnized_;

View File

@ -38,7 +38,7 @@ void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem
optv4.decorationSize.setWidth(en_w);
QStyledItemDelegate::paint(painter, optv4, index);
frame_data *fd;
const frame_data *fd;
PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
if (!record || (fd = record->frameData()) == NULL) {
return;

View File

@ -67,7 +67,7 @@ void packet_list_thaw(void);
void packet_list_next(void);
void packet_list_prev(void);
guint packet_list_append(column_info *cinfo, frame_data *fdata);
frame_data * packet_list_get_row_data(gint row);
frame_data *packet_list_get_row_data(gint row);
void packet_list_set_selected_row(gint row);
void packet_list_enable_color(gboolean enable);
void packet_list_queue_draw(void);