diff --git a/epan/frame_data.h b/epan/frame_data.h index 996f4e1321..bf8842e640 100644 --- a/epan/frame_data.h +++ b/epan/frame_data.h @@ -23,6 +23,10 @@ #ifndef __FRAME_DATA_H__ #define __FRAME_DATA_H__ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + #include #include #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__ */ /* diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 3aa5a31ddc..677bf88403 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -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", diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp index bb593ad0ed..e2adc1f3bc 100644 --- a/ui/qt/packet_list.cpp +++ b/ui/qt/packet_list.cpp @@ -47,12 +47,17 @@ #include "frame_tvbuff.h" -#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include + +// 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 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; diff --git a/ui/qt/packet_list_model.cpp b/ui/qt/packet_list_model.cpp index 0de133d440..78f57f550e 100644 --- a/ui/qt/packet_list_model.cpp +++ b/ui/qt/packet_list_model.cpp @@ -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(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; diff --git a/ui/qt/packet_list_model.h b/ui/qt/packet_list_model.h index 3775f1958a..9c22be5daa 100644 --- a/ui/qt/packet_list_model.h +++ b/ui/qt/packet_list_model.h @@ -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 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 diff --git a/ui/qt/packet_list_record.cpp b/ui/qt/packet_list_record.cpp index 296693b59b..1799ddfc78 100644 --- a/ui/qt/packet_list_record.cpp +++ b/ui/qt/packet_list_record.cpp @@ -33,7 +33,7 @@ #include -QMap cinfo_column_; +QMap 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) { diff --git a/ui/qt/packet_list_record.h b/ui/qt/packet_list_record.h index 18fd3d90ba..a116e62633 100644 --- a/ui/qt/packet_list_record.h +++ b/ui/qt/packet_list_record.h @@ -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 col_text_; frame_data *fdata_; + static QMap cinfo_column_; + /** Has this record been columnized? */ // gboolean columnized_; diff --git a/ui/qt/related_packet_delegate.cpp b/ui/qt/related_packet_delegate.cpp index 11fb34caac..c7964d2e8f 100644 --- a/ui/qt/related_packet_delegate.cpp +++ b/ui/qt/related_packet_delegate.cpp @@ -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(index.internalPointer()); if (!record || (fd = record->frameData()) == NULL) { return; diff --git a/ui/ui_util.h b/ui/ui_util.h index af6335e95d..7ebd59bd3d 100644 --- a/ui/ui_util.h +++ b/ui/ui_util.h @@ -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);