diff --git a/epan/prefs.c b/epan/prefs.c
index d096f28a38..a54cafac3a 100644
--- a/epan/prefs.c
+++ b/epan/prefs.c
@@ -3485,6 +3485,11 @@ prefs_register_modules(void)
"To prevent sorting by mistake (which can take some time to calculate), it can be disabled",
&prefs.gui_packet_list_sortable);
+ prefs_register_uint_preference(gui_module, "packet_list_cached_rows_max",
+ "Maximum cached rows",
+ "Maximum number of rows that can be sorted by columns that require dissection. Increasing this increases memory consumption by caching column text",
+ 10,
+ &prefs.gui_packet_list_cached_rows_max);
prefs_register_bool_preference(gui_module, "interfaces_show_hidden",
"Show hidden interfaces",
@@ -4190,6 +4195,7 @@ pre_init_prefs(void)
prefs.gui_packet_list_show_related = TRUE;
prefs.gui_packet_list_show_minimap = TRUE;
prefs.gui_packet_list_sortable = TRUE;
+ prefs.gui_packet_list_cached_rows_max = 10000;
g_free (prefs.gui_interfaces_hide_types);
prefs.gui_interfaces_hide_types = g_strdup("");
prefs.gui_interfaces_show_hidden = FALSE;
diff --git a/epan/prefs.h b/epan/prefs.h
index 9e6fcff56c..6bfd0ae1ea 100644
--- a/epan/prefs.h
+++ b/epan/prefs.h
@@ -220,6 +220,7 @@ typedef struct _e_prefs {
gboolean gui_packet_list_show_related;
gboolean gui_packet_list_show_minimap;
gboolean gui_packet_list_sortable;
+ guint gui_packet_list_cached_rows_max;
gint gui_decimal_places1; /* Used for type 1 calculations */
gint gui_decimal_places2; /* Used for type 2 calculations */
gint gui_decimal_places3; /* Used for type 3 calculations */
diff --git a/ui/qt/layout_preferences_frame.cpp b/ui/qt/layout_preferences_frame.cpp
index 34d6d2d866..e1a5d99015 100644
--- a/ui/qt/layout_preferences_frame.cpp
+++ b/ui/qt/layout_preferences_frame.cpp
@@ -41,7 +41,7 @@ LayoutPreferencesFrame::LayoutPreferencesFrame(QWidget *parent) :
QStyleOption style_opt;
QString indent_ss = QString(
- "QCheckBox {"
+ "QCheckBox, QLabel {"
" margin-left: %1px;"
"}"
).arg(ui->packetListSeparatorCheckBox->style()->subElementRect(QStyle::SE_CheckBoxContents, &style_opt).left());
@@ -49,6 +49,7 @@ LayoutPreferencesFrame::LayoutPreferencesFrame(QWidget *parent) :
ui->packetListHeaderShowColumnDefinition->setStyleSheet(indent_ss);
ui->packetListHoverStyleCheckbox->setStyleSheet(indent_ss);
ui->packetListAllowSorting->setStyleSheet(indent_ss);
+ ui->packetListCachedRowsLabel->setStyleSheet(indent_ss);
ui->statusBarShowSelectedPacketCheckBox->setStyleSheet(indent_ss);
ui->statusBarShowFileLoadTimeCheckBox->setStyleSheet(indent_ss);
@@ -64,6 +65,8 @@ LayoutPreferencesFrame::LayoutPreferencesFrame(QWidget *parent) :
pref_packet_list_sorting_ = prefFromPrefPtr(&prefs.gui_packet_list_sortable);
ui->packetListAllowSorting->setChecked(prefs_get_bool_value(pref_packet_list_sorting_, pref_stashed));
+ pref_packet_list_cached_rows_max_ = prefFromPrefPtr(&prefs.gui_packet_list_cached_rows_max);
+
pref_show_selected_packet_ = prefFromPrefPtr(&prefs.gui_qt_show_selected_packet);
ui->statusBarShowSelectedPacketCheckBox->setChecked(prefs_get_bool_value(pref_show_selected_packet_, pref_stashed));
@@ -157,6 +160,8 @@ void LayoutPreferencesFrame::updateWidgets()
ui->pane3NoneRadioButton->setChecked(true);
break;
}
+
+ ui->packetListCachedRowsLineEdit->setText(QString::number(prefs_get_uint_value_real(pref_packet_list_cached_rows_max_, pref_stashed)));
}
void LayoutPreferencesFrame::on_layout5ToolButton_toggled(bool checked)
@@ -371,6 +376,15 @@ void LayoutPreferencesFrame::on_packetListAllowSorting_toggled(bool checked)
prefs_set_bool_value(pref_packet_list_sorting_, (gboolean) checked, pref_stashed);
}
+void LayoutPreferencesFrame::on_packetListCachedRowsLineEdit_textEdited(const QString &new_str)
+{
+ bool ok;
+ uint new_uint = new_str.toUInt(&ok, 0);
+ if (ok) {
+ prefs_set_uint_value(pref_packet_list_cached_rows_max_, new_uint, pref_stashed);
+ }
+}
+
void LayoutPreferencesFrame::on_statusBarShowSelectedPacketCheckBox_toggled(bool checked)
{
prefs_set_bool_value(pref_show_selected_packet_, (gboolean) checked, pref_stashed);
diff --git a/ui/qt/layout_preferences_frame.h b/ui/qt/layout_preferences_frame.h
index 372caeae17..6773c5eeb9 100644
--- a/ui/qt/layout_preferences_frame.h
+++ b/ui/qt/layout_preferences_frame.h
@@ -41,6 +41,7 @@ private:
pref_t *pref_packet_header_column_definition_;
pref_t *pref_packet_list_hover_style_;
pref_t *pref_packet_list_sorting_;
+ pref_t *pref_packet_list_cached_rows_max_;
pref_t *pref_show_selected_packet_;
pref_t *pref_show_file_load_time_;
@@ -73,6 +74,7 @@ private slots:
void on_packetListHeaderShowColumnDefinition_toggled(bool checked);
void on_packetListHoverStyleCheckbox_toggled(bool checked);
void on_packetListAllowSorting_toggled(bool checked);
+ void on_packetListCachedRowsLineEdit_textEdited(const QString &new_str);
void on_statusBarShowSelectedPacketCheckBox_toggled(bool checked);
void on_statusBarShowFileLoadTimeCheckBox_toggled(bool checked);
};
diff --git a/ui/qt/layout_preferences_frame.ui b/ui/qt/layout_preferences_frame.ui
index 77a7edf62f..70600706a4 100644
--- a/ui/qt/layout_preferences_frame.ui
+++ b/ui/qt/layout_preferences_frame.ui
@@ -402,6 +402,34 @@
+ -
+
+
-
+
+
+ Maximum number of cached rows (affects sorting)
+
+
+ <html><head/><body><p>If more than this many rows are displayed, then sorting by columns that require packet dissection will be disabled. Increasing this number increases memory consumption by caching column values.</p></body></html>
+
+
+
+ -
+
+
+ <html><head/><body><p>If more than this many rows are displayed, then sorting by columns that require packet dissection will be disabled. Increasing this number increases memory consumption by caching column values.</p></body></html>
+
+
+
+ -
+
+
+ Qt:Horizontal
+
+
+
+
+
-
diff --git a/ui/qt/models/packet_list_model.cpp b/ui/qt/models/packet_list_model.cpp
index a9726a8aa1..7c71e824c6 100644
--- a/ui/qt/models/packet_list_model.cpp
+++ b/ui/qt/models/packet_list_model.cpp
@@ -358,6 +358,27 @@ void PacketListModel::sort(int column, Qt::SortOrder order)
QString col_title = get_column_title(column);
+ if (text_sort_column_ >= 0 && (guint)visible_rows_.count() > prefs.gui_packet_list_cached_rows_max) {
+ /* Column not based on frame data but by column text that requires
+ * dissection, so to sort in a reasonable amount of time the column
+ * text needs to be cached.
+ */
+ /* If the sort is being triggered because the columns were already
+ * sorted and the filter is being cleared (or changed to something
+ * else with more rows than fit in the cache), then the temporary
+ * message will be immediately overwritten with the standard capture
+ * statistics by the packets_bar_update() call after thawing the rows.
+ * It will still blink yellow, and the user will get the message if
+ * they then click on the header file (wondering why it didn't sort.)
+ */
+ if (col_title.isEmpty()) {
+ col_title = tr("Column");
+ }
+ QString temp_msg = tr("%1 can only be sorted with %2 or fewer visible rows; increase cache size in Layout preferences").arg(col_title).arg(prefs.gui_packet_list_cached_rows_max);
+ mainApp->pushStatus(MainApplication::TemporaryStatus, temp_msg);
+ return;
+ }
+
// XXX Use updateProgress instead. We'd have to switch from std::sort to
// something we can interrupt.
if (!col_title.isEmpty()) {
diff --git a/ui/qt/models/packet_list_record.h b/ui/qt/models/packet_list_record.h
index 5afe37b7ba..2a6db75cba 100644
--- a/ui/qt/models/packet_list_record.h
+++ b/ui/qt/models/packet_list_record.h
@@ -45,6 +45,10 @@ public:
int columnTextSize(const char *str);
static void invalidateAllRecords() { col_text_cache_.clear(); }
+ /* In Qt 6, QCache maxCost is a qsizetype, but the QAbstractItemModel
+ * number of rows is still an int, so we're limited to INT_MAX anyway.
+ */
+ static void setMaxCache(int cost) { col_text_cache_.setMaxCost(cost); }
static void resetColumns(column_info *cinfo);
static void resetColorization() { rows_color_ver_++; }
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index 2f35683609..227fc139c3 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -252,6 +252,12 @@ PacketList::PacketList(QWidget *parent) :
connect(mainApp, SIGNAL(addressResolutionChanged()), this, SLOT(redrawVisiblePacketsDontSelectCurrent()));
connect(mainApp, SIGNAL(columnDataChanged()), this, SLOT(redrawVisiblePacketsDontSelectCurrent()));
connect(mainApp, &MainApplication::preferencesChanged, this, [=]() {
+ /* The pref is a uint but QCache maxCost is a signed int (/
+ * qsizetype in Qt 6). Note that QAbstractItemModel row numbers
+ * are ints, not unsigned ints, so we're limited to INT_MAX
+ * rows anyway.
+ */
+ PacketListRecord::setMaxCache(prefs.gui_packet_list_cached_rows_max > INT_MAX ? INT_MAX : prefs.gui_packet_list_cached_rows_max);
if ((bool) (prefs.gui_packet_list_sortable) != isSortingEnabled()) {
setSortingEnabled(prefs.gui_packet_list_sortable);
}