aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorRoland Knall <rknall@gmail.com>2022-06-19 11:18:16 +0200
committerRoland Knall <rknall@gmail.com>2022-06-19 16:39:35 +0200
commit2b4878d452a5b38924168a2baa6a59ddeddc0c4e (patch)
tree5056f962261bddda5ceea367004b3507b31b72b0 /ui
parentf75f577579e552aa6c6f3f59b101f1febc49fc83 (diff)
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
Diffstat (limited to 'ui')
-rw-r--r--ui/qt/conversation_dialog.cpp2
-rw-r--r--ui/qt/endpoint_dialog.cpp2
-rw-r--r--ui/qt/widgets/traffic_tab.cpp39
-rw-r--r--ui/qt/widgets/traffic_tab.h18
-rw-r--r--ui/qt/widgets/traffic_tree.cpp122
-rw-r--r--ui/qt/widgets/traffic_tree.h36
-rw-r--r--ui/recent.c20
-rw-r--r--ui/recent.h2
8 files changed, 229 insertions, 12 deletions
diff --git a/ui/qt/conversation_dialog.cpp b/ui/qt/conversation_dialog.cpp
index 1dc5f02b2a..9521144ea9 100644
--- a/ui/qt/conversation_dialog.cpp
+++ b/ui/qt/conversation_dialog.cpp
@@ -95,7 +95,7 @@ ConversationDialog::ConversationDialog(QWidget &parent, CaptureFile &cf) :
{
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_DURATION, &createDelegate);
trafficTab()->setFilter(cf.displayFilter());
diff --git a/ui/qt/endpoint_dialog.cpp b/ui/qt/endpoint_dialog.cpp
index c1a81235f8..9cb2dfb32a 100644
--- a/ui/qt/endpoint_dialog.cpp
+++ b/ui/qt/endpoint_dialog.cpp
@@ -69,7 +69,7 @@ EndpointDialog::EndpointDialog(QWidget &parent, CaptureFile &cf) :
{
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());
displayFilterCheckBox()->setChecked(cf.displayFilter().length() > 0);
connect(trafficTab(), &TrafficTab::filterAction, this, &EndpointDialog::filterAction);
diff --git a/ui/qt/widgets/traffic_tab.cpp b/ui/qt/widgets/traffic_tab.cpp
index 65807425a4..637b2d6310 100644
--- a/ui/qt/widgets/traffic_tab.cpp
+++ b/ui/qt/widgets/traffic_tab.cpp
@@ -22,6 +22,7 @@
#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_types_list.h>
#include <ui/qt/widgets/detachable_tabwidget.h>
#include <QStringList>
@@ -176,6 +177,24 @@ bool TrafficDataFilterProxy::lessThan(const QModelIndex &source_left, const QMod
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) :
DetachableTabWidget(parent)
@@ -189,14 +208,17 @@ TrafficTab::TrafficTab(QWidget * parent) :
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);
- _allProtocols = allProtocols;
+
+ _allProtocols = trafficList->protocols();
if (createModel)
_createModel = createModel;
- setOpenTabs(openTabs);
+ _recentColumnList = recentColumnList;
+
+ setOpenTabs(trafficList->selectedProtocols());
}
void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate)
@@ -228,7 +250,7 @@ void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate)
QTreeView * TrafficTab::createTree(int protoId)
{
- TrafficTree * tree = new TrafficTree(tabBasename(), this);
+ TrafficTree * tree = new TrafficTree(tabBasename(), _recentColumnList, this);
if (_createModel) {
ATapDataModel * model = _createModel(protoId, "");
@@ -253,6 +275,8 @@ QTreeView * TrafficTab::createTree(int protoId)
tree->setSelectionModel(ism);
connect(ism, &QItemSelectionModel::currentChanged, this, &TrafficTab::doCurrentIndexChange);
+ tree->applyRecentColumns();
+
tree->sortByColumn(0, Qt::AscendingOrder);
connect(proxyModel, &TrafficDataFilterProxy::modelReset, this, [tree]() {
@@ -262,6 +286,13 @@ QTreeView * TrafficTab::createTree(int protoId)
}
});
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;
diff --git a/ui/qt/widgets/traffic_tab.h b/ui/qt/widgets/traffic_tab.h
index c58a7ed592..a1605255a6 100644
--- a/ui/qt/widgets/traffic_tab.h
+++ b/ui/qt/widgets/traffic_tab.h
@@ -12,9 +12,12 @@
#include "config.h"
+#include <glib.h>
+
#include <ui/qt/models/atap_data_model.h>
#include <ui/qt/filter_action.h>
#include <ui/qt/widgets/detachable_tabwidget.h>
+#include <ui/qt/widgets/traffic_types_list.h>
#include <QTabWidget>
#include <QTreeView>
@@ -67,10 +70,17 @@ class TrafficDataFilterProxy : public QSortFilterProxyModel
public:
TrafficDataFilterProxy(QObject *parent = nullptr);
+ void setColumnVisibility(int column, bool visible);
+ bool columnVisible(int column) const;
+
protected:
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;
+private:
+ QList<int> hideColumns_;
+
};
/**
@@ -97,13 +107,13 @@ public:
* 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 allProtocols a list of all possible protocols. It's order will set the tab oder
- * @param openTabs a list of protocol ids to open at start of dialog
+ * @param trafficList an element of traffictypeslist, which handles all profile selections
+ * @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
*
* @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
@@ -219,6 +229,7 @@ signals:
void retapRequired();
void disablingTaps();
void tabsChanged(QList<int> protocols);
+ void columnsHaveChanged(QList<int> columns);
protected slots:
@@ -230,6 +241,7 @@ private:
QMap<int, int> _tabs;
ATapModelCallback _createModel;
QMap<int, ATapCreateDelegate> _createDelegates;
+ GList ** _recentColumnList;
bool _disableTaps;
bool _nameResolution;
diff --git a/ui/qt/widgets/traffic_tree.cpp b/ui/qt/widgets/traffic_tree.cpp
index 3e370da83c..40f34fa12d 100644
--- a/ui/qt/widgets/traffic_tree.cpp
+++ b/ui/qt/widgets/traffic_tree.cpp
@@ -25,6 +25,7 @@
#include <ui/qt/filter_action.h>
#include <ui/qt/models/atap_data_model.h>
#include <ui/qt/utils/variant_pointer.h>
+#include <ui/qt/widgets/traffic_tab.h>
#include <ui/qt/widgets/traffic_tree.h>
#include <QStringList>
@@ -39,20 +40,120 @@
#include <QJsonArray>
#include <QJsonObject>
#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)
{
_tapEnabled = true;
_saveRaw = true;
_baseName = baseName;
_exportRole = ATapDataModel::UNFORMATTED_DISPLAYDATA;
+ _header = nullptr;
setAlternatingRowColors(true);
setRootIsDecorated(false);
setSortingEnabled(true);
setContextMenuPolicy(Qt::CustomContextMenu);
+ _header = new TrafficTreeHeaderView(recentColumnList);
+ setHeader(_header);
+
+ connect(_header, &TrafficTreeHeaderView::columnsHaveChanged, this, &TrafficTree::columnsHaveChanged);
connect(this, &QTreeView::customContextMenuRequested, this, &TrafficTree::customContextMenu);
}
@@ -277,3 +378,22 @@ void TrafficTree::disableTap()
return;
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();
+}
diff --git a/ui/qt/widgets/traffic_tree.h b/ui/qt/widgets/traffic_tree.h
index 34f87b6f37..037a28d099 100644
--- a/ui/qt/widgets/traffic_tree.h
+++ b/ui/qt/widgets/traffic_tree.h
@@ -12,6 +12,8 @@
#include "config.h"
+#include <glib.h>
+
#include <ui/recent.h>
#include <ui/qt/models/atap_data_model.h>
@@ -19,6 +21,29 @@
#include <QTreeView>
#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
{
@@ -35,7 +60,7 @@ public:
CLIPBOARD_JSON /* export as JSON */
} 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
@@ -48,12 +73,16 @@ public:
*/
QMenu * createCopyMenu(QWidget * parent = nullptr);
+ void applyRecentColumns();
+
signals:
void filterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type);
+ void columnsHaveChanged(QList<int> columns);
public slots:
void tapListenerEnabled(bool enable);
void disableTap();
+ void columnsChanged(QList<int> columns);
private:
bool _tapEnabled;
@@ -61,18 +90,21 @@ private:
bool _saveRaw;
QString _baseName;
+ TrafficTreeHeaderView * _header;
+
ATapDataModel * dataModel();
QMenu * createActionSubMenu(FilterAction::Action cur_action, QModelIndex idx, bool isConversation);
void copyToClipboard(eTrafficTreeClipboard type);
+ friend class TrafficTreeHeaderView;
+
private slots:
void customContextMenu(const QPoint &pos);
void useFilterAction();
void clipboardAction();
void resizeAction();
void toggleSaveRawAction();
-
};
#endif // TRAFFIC_TREE_H
diff --git a/ui/recent.c b/ui/recent.c
index 5f1f713a2e..c59d67da81 100644
--- a/ui/recent.c
+++ b/ui/recent.c
@@ -60,7 +60,9 @@
#define RECENT_LAST_USED_PROFILE "gui.last_used_profile"
#define RECENT_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen_remembered_dir"
#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_COLUMNS "gui.endpoint_tabs_columns"
#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_TOOLBAR_SHOW "gui.additional_toolbar_show"
@@ -918,12 +920,24 @@ write_profile_recent(void)
fprintf(rf, RECENT_GUI_CONVERSATION_TABS ": %s\n", 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, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
string_list = join_string_list(recent.endpoint_tabs);
fprintf(rf, RECENT_GUI_ENDPOINT_TABS ": %s\n", 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",
RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES,
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;
} else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS) == 0) {
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) {
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) {
parse_recent_boolean(value, &recent.gui_rlc_use_pdus_from_mac);
} 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.interface_toolbars, g_free);
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_columns);
prefs_clear_string_list(recent.custom_colors);
}
diff --git a/ui/recent.h b/ui/recent.h
index beb94a96a9..682f25d2ed 100644
--- a/ui/recent.h
+++ b/ui/recent.h
@@ -128,7 +128,9 @@ typedef struct recent_settings_tag {
gboolean sys_warn_if_no_capture;
GList *col_width_list; /* column widths */
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_columns; /* save the columns for endpoint dialogs */
gchar *gui_fileopen_remembered_dir; /* folder of last capture loaded in File Open dialog */
gboolean gui_rlc_use_pdus_from_mac;
GList *custom_colors;