Qt: Hide columns for traffic tree

Allow columns to be hidden for the traffic tree dialogs
Conversations and Endpoints and store the information profile
specific
This commit is contained in:
Roland Knall 2022-06-19 11:18:16 +02:00
parent f75f577579
commit 2b4878d452
9 changed files with 232 additions and 12 deletions

View File

@ -40,6 +40,7 @@ wsbuglink:17779[]
- The dialog elements have been moved to make it easier to handle for new users. - The dialog elements have been moved to make it easier to handle for new users.
- Selection of tap elements is done via list - Selection of tap elements is done via list
- All configurations and options are done via a left side button row - All configurations and options are done via a left side button row
- Columns for the Conversations and Endpoint dialogs can be hidden by context menu
* The PCRE2 library (https://www.pcre.org/) is now a required dependency to build Wireshark. * The PCRE2 library (https://www.pcre.org/) is now a required dependency to build Wireshark.
@ -77,6 +78,8 @@ The following features are new (or have been significantly updated) since versio
* The Windows installers now ship with Qt 6.2.3. * The Windows installers now ship with Qt 6.2.3.
They previously shipped with Qt 6.2.4. They previously shipped with Qt 6.2.4.
* The Conversation and Endpoint dialogs have been reworked extensively
The following features are new (or have been significantly updated) since version 3.6.0: The following features are new (or have been significantly updated) since version 3.6.0:
* The Windows installers now ship with Npcap 1.60. * The Windows installers now ship with Npcap 1.60.

View File

@ -95,7 +95,7 @@ ConversationDialog::ConversationDialog(QWidget &parent, CaptureFile &cf) :
{ {
trafficList()->setProtocolInfo(table_name_, &(recent.conversation_tabs)); trafficList()->setProtocolInfo(table_name_, &(recent.conversation_tabs));
trafficTab()->setProtocolInfo(table_name_, trafficList()->protocols(), trafficList()->selectedProtocols(), &createModel); trafficTab()->setProtocolInfo(table_name_, trafficList(), &(recent.conversation_tabs_columns), &createModel);
trafficTab()->setDelegate(CONV_COLUMN_START, &createDelegate); trafficTab()->setDelegate(CONV_COLUMN_START, &createDelegate);
trafficTab()->setDelegate(CONV_COLUMN_DURATION, &createDelegate); trafficTab()->setDelegate(CONV_COLUMN_DURATION, &createDelegate);
trafficTab()->setFilter(cf.displayFilter()); trafficTab()->setFilter(cf.displayFilter());

View File

@ -69,7 +69,7 @@ EndpointDialog::EndpointDialog(QWidget &parent, CaptureFile &cf) :
{ {
trafficList()->setProtocolInfo(table_name_, &(recent.endpoint_tabs)); trafficList()->setProtocolInfo(table_name_, &(recent.endpoint_tabs));
trafficTab()->setProtocolInfo(table_name_, trafficList()->protocols(), trafficList()->selectedProtocols(), &createModel); trafficTab()->setProtocolInfo(table_name_, trafficList(), &(recent.endpoint_tabs_columns), &createModel);
trafficTab()->setFilter(cf.displayFilter()); trafficTab()->setFilter(cf.displayFilter());
displayFilterCheckBox()->setChecked(cf.displayFilter().length() > 0); displayFilterCheckBox()->setChecked(cf.displayFilter().length() > 0);
connect(trafficTab(), &TrafficTab::filterAction, this, &EndpointDialog::filterAction); connect(trafficTab(), &TrafficTab::filterAction, this, &EndpointDialog::filterAction);

View File

@ -22,6 +22,7 @@
#include <ui/qt/utils/variant_pointer.h> #include <ui/qt/utils/variant_pointer.h>
#include <ui/qt/widgets/traffic_tab.h> #include <ui/qt/widgets/traffic_tab.h>
#include <ui/qt/widgets/traffic_tree.h> #include <ui/qt/widgets/traffic_tree.h>
#include <ui/qt/widgets/traffic_types_list.h>
#include <ui/qt/widgets/detachable_tabwidget.h> #include <ui/qt/widgets/detachable_tabwidget.h>
#include <QStringList> #include <QStringList>
@ -176,6 +177,24 @@ bool TrafficDataFilterProxy::lessThan(const QModelIndex &source_left, const QMod
return QSortFilterProxyModel::lessThan(source_left, source_right); return QSortFilterProxyModel::lessThan(source_left, source_right);
} }
bool TrafficDataFilterProxy::filterAcceptsColumn(int source_column, const QModelIndex &) const
{
return (!hideColumns_.contains(source_column));
}
void TrafficDataFilterProxy::setColumnVisibility(int column, bool visible)
{
hideColumns_.removeAll(column);
if (!visible)
hideColumns_.append(column);
invalidateFilter();
}
bool TrafficDataFilterProxy::columnVisible(int column) const
{
return ! hideColumns_.contains(column);
}
TrafficTab::TrafficTab(QWidget * parent) : TrafficTab::TrafficTab(QWidget * parent) :
DetachableTabWidget(parent) DetachableTabWidget(parent)
@ -189,14 +208,17 @@ TrafficTab::TrafficTab(QWidget * parent) :
TrafficTab::~TrafficTab() TrafficTab::~TrafficTab()
{} {}
void TrafficTab::setProtocolInfo(QString tableName, QList<int> allProtocols, QList<int> openTabs, ATapModelCallback createModel) void TrafficTab::setProtocolInfo(QString tableName, TrafficTypesList * trafficList, GList ** recentColumnList, ATapModelCallback createModel)
{ {
setTabBasename(tableName); setTabBasename(tableName);
_allProtocols = allProtocols;
_allProtocols = trafficList->protocols();
if (createModel) if (createModel)
_createModel = createModel; _createModel = createModel;
setOpenTabs(openTabs); _recentColumnList = recentColumnList;
setOpenTabs(trafficList->selectedProtocols());
} }
void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate) void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate)
@ -228,7 +250,7 @@ void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate)
QTreeView * TrafficTab::createTree(int protoId) QTreeView * TrafficTab::createTree(int protoId)
{ {
TrafficTree * tree = new TrafficTree(tabBasename(), this); TrafficTree * tree = new TrafficTree(tabBasename(), _recentColumnList, this);
if (_createModel) { if (_createModel) {
ATapDataModel * model = _createModel(protoId, ""); ATapDataModel * model = _createModel(protoId, "");
@ -253,6 +275,8 @@ QTreeView * TrafficTab::createTree(int protoId)
tree->setSelectionModel(ism); tree->setSelectionModel(ism);
connect(ism, &QItemSelectionModel::currentChanged, this, &TrafficTab::doCurrentIndexChange); connect(ism, &QItemSelectionModel::currentChanged, this, &TrafficTab::doCurrentIndexChange);
tree->applyRecentColumns();
tree->sortByColumn(0, Qt::AscendingOrder); tree->sortByColumn(0, Qt::AscendingOrder);
connect(proxyModel, &TrafficDataFilterProxy::modelReset, this, [tree]() { connect(proxyModel, &TrafficDataFilterProxy::modelReset, this, [tree]() {
@ -262,6 +286,13 @@ QTreeView * TrafficTab::createTree(int protoId)
} }
}); });
connect(proxyModel, &TrafficDataFilterProxy::modelReset, this, &TrafficTab::modelReset); connect(proxyModel, &TrafficDataFilterProxy::modelReset, this, &TrafficTab::modelReset);
/* If the columns for the tree have changed, contact the tab. By also having the tab
* columns changed signal connecting back to the tree, it will propagate to all trees
* registered with this tab. Attention, this heavily relies on the fact, that all
* tree data models are identical */
connect(tree, &TrafficTree::columnsHaveChanged, this, &TrafficTab::columnsHaveChanged);
connect(this, &TrafficTab::columnsHaveChanged, tree, &TrafficTree::columnsChanged);
} }
return tree; return tree;

View File

@ -12,9 +12,12 @@
#include "config.h" #include "config.h"
#include <glib.h>
#include <ui/qt/models/atap_data_model.h> #include <ui/qt/models/atap_data_model.h>
#include <ui/qt/filter_action.h> #include <ui/qt/filter_action.h>
#include <ui/qt/widgets/detachable_tabwidget.h> #include <ui/qt/widgets/detachable_tabwidget.h>
#include <ui/qt/widgets/traffic_types_list.h>
#include <QTabWidget> #include <QTabWidget>
#include <QTreeView> #include <QTreeView>
@ -67,10 +70,17 @@ class TrafficDataFilterProxy : public QSortFilterProxyModel
public: public:
TrafficDataFilterProxy(QObject *parent = nullptr); TrafficDataFilterProxy(QObject *parent = nullptr);
void setColumnVisibility(int column, bool visible);
bool columnVisible(int column) const;
protected: protected:
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
virtual bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const;
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const; virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
private:
QList<int> hideColumns_;
}; };
/** /**
@ -97,13 +107,13 @@ public:
* without having to removing the predefined object during setup of the UI. * without having to removing the predefined object during setup of the UI.
* *
* @param tableName The name for the table. Used for the protocol selection button * @param tableName The name for the table. Used for the protocol selection button
* @param allProtocols a list of all possible protocols. It's order will set the tab oder * @param trafficList an element of traffictypeslist, which handles all profile selections
* @param openTabs a list of protocol ids to open at start of dialog * @param recentColumnList a list of columns to be displayed for this traffic type
* @param createModel A callback, which will create the correct model for the trees * @param createModel A callback, which will create the correct model for the trees
* *
* @see ATapModelCallback * @see ATapModelCallback
*/ */
void setProtocolInfo(QString tableName, QList<int> allProtocols, QList<int> openTabs, ATapModelCallback createModel); void setProtocolInfo(QString tableName, TrafficTypesList * trafficList, GList ** recentColumnList, ATapModelCallback createModel);
/** /**
* @brief Set the Delegate object for a specific column * @brief Set the Delegate object for a specific column
@ -219,6 +229,7 @@ signals:
void retapRequired(); void retapRequired();
void disablingTaps(); void disablingTaps();
void tabsChanged(QList<int> protocols); void tabsChanged(QList<int> protocols);
void columnsHaveChanged(QList<int> columns);
protected slots: protected slots:
@ -230,6 +241,7 @@ private:
QMap<int, int> _tabs; QMap<int, int> _tabs;
ATapModelCallback _createModel; ATapModelCallback _createModel;
QMap<int, ATapCreateDelegate> _createDelegates; QMap<int, ATapCreateDelegate> _createDelegates;
GList ** _recentColumnList;
bool _disableTaps; bool _disableTaps;
bool _nameResolution; bool _nameResolution;

View File

@ -25,6 +25,7 @@
#include <ui/qt/filter_action.h> #include <ui/qt/filter_action.h>
#include <ui/qt/models/atap_data_model.h> #include <ui/qt/models/atap_data_model.h>
#include <ui/qt/utils/variant_pointer.h> #include <ui/qt/utils/variant_pointer.h>
#include <ui/qt/widgets/traffic_tab.h>
#include <ui/qt/widgets/traffic_tree.h> #include <ui/qt/widgets/traffic_tree.h>
#include <QStringList> #include <QStringList>
@ -39,20 +40,120 @@
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QHeaderView>
TrafficTree::TrafficTree(QString baseName, QWidget *parent) : TrafficTreeHeaderView::TrafficTreeHeaderView(GList ** recentColumnList, QWidget * parent):
QHeaderView(Qt::Horizontal, parent)
{
_recentColumnList = recentColumnList;
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &QHeaderView::customContextMenuRequested, this, &TrafficTreeHeaderView::headerContextMenu);
}
TrafficTreeHeaderView::~TrafficTreeHeaderView()
{}
void TrafficTreeHeaderView::headerContextMenu(const QPoint &pos)
{
TrafficTree * tree = qobject_cast<TrafficTree *>(parent());
if (!tree)
return;
TrafficDataFilterProxy * proxy = qobject_cast<TrafficDataFilterProxy *>(tree->model());
if (sender() != this || ! proxy)
return;
QMenu ctxMenu;
for (int col = 0; col < tree->dataModel()->columnCount(); col++)
{
QString name = tree->dataModel()->headerData(col).toString();
QAction * action = new QAction(name);
action->setCheckable(true);
action->setChecked(proxy->columnVisible(col));
action->setProperty("col_nr", col);
ctxMenu.addAction(action);
connect(action, &QAction::triggered, this, &TrafficTreeHeaderView::columnTriggered);
}
ctxMenu.exec(mapToGlobal(pos));
}
void TrafficTreeHeaderView::applyRecent()
{
TrafficTree * tree = qobject_cast<TrafficTree *>(parent());
if (!tree)
return;
QList<int> columns;
for (GList * endTab = *_recentColumnList; endTab; endTab = endTab->next) {
QString colStr = QString((const char *)endTab->data);
bool ok = false;
int col = colStr.toInt(&ok);
if (ok)
columns << col;
}
if (columns.count() > 0) {
TrafficDataFilterProxy * proxy = qobject_cast<TrafficDataFilterProxy *>(tree->model());
for (int col = 0; col < tree->dataModel()->columnCount(); col++) {
proxy->setColumnVisibility(col, columns.contains(col));
}
}
}
void TrafficTreeHeaderView::columnTriggered(bool checked)
{
TrafficTree * tree = qobject_cast<TrafficTree *>(parent());
if (!tree)
return;
TrafficDataFilterProxy * proxy = qobject_cast<TrafficDataFilterProxy *>(tree->model());
QAction * entry = qobject_cast<QAction *>(sender());
if (! proxy || ! entry || ! entry->property("col_nr").isValid())
return;
int col = entry->property("col_nr").toInt();
proxy->setColumnVisibility(col, checked);
prefs_clear_string_list(*_recentColumnList);
*_recentColumnList = NULL;
QList<int> visible;
for (int col = 0; col < tree->dataModel()->columnCount(); col++) {
if (proxy->columnVisible(col)) {
visible << col;
gchar *nr = qstring_strdup(QString::number(col));
*_recentColumnList = g_list_append(*_recentColumnList, nr);
}
}
emit columnsHaveChanged(visible);
}
TrafficTree::TrafficTree(QString baseName, GList ** recentColumnList, QWidget *parent) :
QTreeView(parent) QTreeView(parent)
{ {
_tapEnabled = true; _tapEnabled = true;
_saveRaw = true; _saveRaw = true;
_baseName = baseName; _baseName = baseName;
_exportRole = ATapDataModel::UNFORMATTED_DISPLAYDATA; _exportRole = ATapDataModel::UNFORMATTED_DISPLAYDATA;
_header = nullptr;
setAlternatingRowColors(true); setAlternatingRowColors(true);
setRootIsDecorated(false); setRootIsDecorated(false);
setSortingEnabled(true); setSortingEnabled(true);
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
_header = new TrafficTreeHeaderView(recentColumnList);
setHeader(_header);
connect(_header, &TrafficTreeHeaderView::columnsHaveChanged, this, &TrafficTree::columnsHaveChanged);
connect(this, &QTreeView::customContextMenuRequested, this, &TrafficTree::customContextMenu); connect(this, &QTreeView::customContextMenuRequested, this, &TrafficTree::customContextMenu);
} }
@ -277,3 +378,22 @@ void TrafficTree::disableTap()
return; return;
model->disableTap(); model->disableTap();
} }
void TrafficTree::applyRecentColumns()
{
if (_header)
_header->applyRecent();
}
void TrafficTree::columnsChanged(QList<int> columns)
{
TrafficDataFilterProxy * proxy = qobject_cast<TrafficDataFilterProxy *>(model());
if (!proxy)
return;
for (int col = 0; col < dataModel()->columnCount(); col++) {
proxy->setColumnVisibility(col, columns.contains(col));
}
resizeAction();
}

View File

@ -12,6 +12,8 @@
#include "config.h" #include "config.h"
#include <glib.h>
#include <ui/recent.h> #include <ui/recent.h>
#include <ui/qt/models/atap_data_model.h> #include <ui/qt/models/atap_data_model.h>
@ -19,6 +21,29 @@
#include <QTreeView> #include <QTreeView>
#include <QMenu> #include <QMenu>
#include <QHeaderView>
class TrafficTreeHeaderView : public QHeaderView
{
Q_OBJECT
public:
TrafficTreeHeaderView(GList ** recentColumnList, QWidget * parent = nullptr);
~TrafficTreeHeaderView();
void applyRecent();
signals:
void columnsHaveChanged(QList<int> visible);
private:
GList ** _recentColumnList;
private slots:
void headerContextMenu(const QPoint &pos);
void columnTriggered(bool checked = false);
};
class TrafficTree : public QTreeView class TrafficTree : public QTreeView
{ {
@ -35,7 +60,7 @@ public:
CLIPBOARD_JSON /* export as JSON */ CLIPBOARD_JSON /* export as JSON */
} eTrafficTreeClipboard; } eTrafficTreeClipboard;
TrafficTree(QString baseName, QWidget *parent = nullptr); TrafficTree(QString baseName, GList ** recentColumnList, QWidget *parent = nullptr);
/** /**
* @brief Create a menu containing clipboard copy entries for this tab * @brief Create a menu containing clipboard copy entries for this tab
@ -48,12 +73,16 @@ public:
*/ */
QMenu * createCopyMenu(QWidget * parent = nullptr); QMenu * createCopyMenu(QWidget * parent = nullptr);
void applyRecentColumns();
signals: signals:
void filterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type); void filterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type);
void columnsHaveChanged(QList<int> columns);
public slots: public slots:
void tapListenerEnabled(bool enable); void tapListenerEnabled(bool enable);
void disableTap(); void disableTap();
void columnsChanged(QList<int> columns);
private: private:
bool _tapEnabled; bool _tapEnabled;
@ -61,18 +90,21 @@ private:
bool _saveRaw; bool _saveRaw;
QString _baseName; QString _baseName;
TrafficTreeHeaderView * _header;
ATapDataModel * dataModel(); ATapDataModel * dataModel();
QMenu * createActionSubMenu(FilterAction::Action cur_action, QModelIndex idx, bool isConversation); QMenu * createActionSubMenu(FilterAction::Action cur_action, QModelIndex idx, bool isConversation);
void copyToClipboard(eTrafficTreeClipboard type); void copyToClipboard(eTrafficTreeClipboard type);
friend class TrafficTreeHeaderView;
private slots: private slots:
void customContextMenu(const QPoint &pos); void customContextMenu(const QPoint &pos);
void useFilterAction(); void useFilterAction();
void clipboardAction(); void clipboardAction();
void resizeAction(); void resizeAction();
void toggleSaveRawAction(); void toggleSaveRawAction();
}; };
#endif // TRAFFIC_TREE_H #endif // TRAFFIC_TREE_H

View File

@ -60,7 +60,9 @@
#define RECENT_LAST_USED_PROFILE "gui.last_used_profile" #define RECENT_LAST_USED_PROFILE "gui.last_used_profile"
#define RECENT_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen_remembered_dir" #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen_remembered_dir"
#define RECENT_GUI_CONVERSATION_TABS "gui.conversation_tabs" #define RECENT_GUI_CONVERSATION_TABS "gui.conversation_tabs"
#define RECENT_GUI_CONVERSATION_TABS_COLUMNS "gui.conversation_tabs_columns"
#define RECENT_GUI_ENDPOINT_TABS "gui.endpoint_tabs" #define RECENT_GUI_ENDPOINT_TABS "gui.endpoint_tabs"
#define RECENT_GUI_ENDPOINT_TABS_COLUMNS "gui.endpoint_tabs_columns"
#define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES "gui.rlc_pdus_from_mac_frames" #define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES "gui.rlc_pdus_from_mac_frames"
#define RECENT_GUI_CUSTOM_COLORS "gui.custom_colors" #define RECENT_GUI_CUSTOM_COLORS "gui.custom_colors"
#define RECENT_GUI_TOOLBAR_SHOW "gui.additional_toolbar_show" #define RECENT_GUI_TOOLBAR_SHOW "gui.additional_toolbar_show"
@ -918,12 +920,24 @@ write_profile_recent(void)
fprintf(rf, RECENT_GUI_CONVERSATION_TABS ": %s\n", string_list); fprintf(rf, RECENT_GUI_CONVERSATION_TABS ": %s\n", string_list);
g_free(string_list); g_free(string_list);
fprintf(rf, "\n# Conversation dialog tabs columns.\n");
fprintf(rf, "# List of conversation columns numbers.\n");
string_list = join_string_list(recent.conversation_tabs_columns);
fprintf(rf, RECENT_GUI_CONVERSATION_TABS_COLUMNS ": %s\n", string_list);
g_free(string_list);
fprintf(rf, "\n# Open endpoint dialog tabs.\n"); fprintf(rf, "\n# Open endpoint dialog tabs.\n");
fprintf(rf, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n"); fprintf(rf, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
string_list = join_string_list(recent.endpoint_tabs); string_list = join_string_list(recent.endpoint_tabs);
fprintf(rf, RECENT_GUI_ENDPOINT_TABS ": %s\n", string_list); fprintf(rf, RECENT_GUI_ENDPOINT_TABS ": %s\n", string_list);
g_free(string_list); g_free(string_list);
fprintf(rf, "\n# Endpoint dialog tabs columns.\n");
fprintf(rf, "# List of endpoint columns numbers.\n");
string_list = join_string_list(recent.endpoint_tabs_columns);
fprintf(rf, RECENT_GUI_ENDPOINT_TABS_COLUMNS ": %s\n", string_list);
g_free(string_list);
write_recent_boolean(rf, "For RLC stats, whether to use RLC PDUs found inside MAC frames", write_recent_boolean(rf, "For RLC stats, whether to use RLC PDUs found inside MAC frames",
RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES,
recent.gui_rlc_use_pdus_from_mac); recent.gui_rlc_use_pdus_from_mac);
@ -1122,8 +1136,12 @@ read_set_recent_pair_static(gchar *key, const gchar *value,
recent.has_gui_geometry_main_lower_pane = TRUE; recent.has_gui_geometry_main_lower_pane = TRUE;
} else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS) == 0) { } else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS) == 0) {
recent.conversation_tabs = prefs_get_string_list(value); recent.conversation_tabs = prefs_get_string_list(value);
} else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS_COLUMNS) == 0) {
recent.conversation_tabs_columns = prefs_get_string_list(value);
} else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS) == 0) { } else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS) == 0) {
recent.endpoint_tabs = prefs_get_string_list(value); recent.endpoint_tabs = prefs_get_string_list(value);
} else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS_COLUMNS) == 0) {
recent.endpoint_tabs_columns = prefs_get_string_list(value);
} else if (strcmp(key, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES) == 0) { } else if (strcmp(key, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES) == 0) {
parse_recent_boolean(value, &recent.gui_rlc_use_pdus_from_mac); parse_recent_boolean(value, &recent.gui_rlc_use_pdus_from_mac);
} else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) { } else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) {
@ -1611,6 +1629,8 @@ recent_cleanup(void)
g_list_free_full(recent.gui_additional_toolbars, g_free); g_list_free_full(recent.gui_additional_toolbars, g_free);
g_list_free_full(recent.interface_toolbars, g_free); g_list_free_full(recent.interface_toolbars, g_free);
prefs_clear_string_list(recent.conversation_tabs); prefs_clear_string_list(recent.conversation_tabs);
prefs_clear_string_list(recent.conversation_tabs_columns);
prefs_clear_string_list(recent.endpoint_tabs); prefs_clear_string_list(recent.endpoint_tabs);
prefs_clear_string_list(recent.endpoint_tabs_columns);
prefs_clear_string_list(recent.custom_colors); prefs_clear_string_list(recent.custom_colors);
} }

View File

@ -128,7 +128,9 @@ typedef struct recent_settings_tag {
gboolean sys_warn_if_no_capture; gboolean sys_warn_if_no_capture;
GList *col_width_list; /* column widths */ GList *col_width_list; /* column widths */
GList *conversation_tabs; /* enabled conversation dialog tabs */ GList *conversation_tabs; /* enabled conversation dialog tabs */
GList *conversation_tabs_columns; /* save the columns for conversation dialogs */
GList *endpoint_tabs; /* enabled endpoint dialog tabs */ GList *endpoint_tabs; /* enabled endpoint dialog tabs */
GList *endpoint_tabs_columns; /* save the columns for endpoint dialogs */
gchar *gui_fileopen_remembered_dir; /* folder of last capture loaded in File Open dialog */ gchar *gui_fileopen_remembered_dir; /* folder of last capture loaded in File Open dialog */
gboolean gui_rlc_use_pdus_from_mac; gboolean gui_rlc_use_pdus_from_mac;
GList *custom_colors; GList *custom_colors;