2019-06-12 16:35:29 -07:00
/* packet_list_header.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
* Copyright 1998 Gerald Combs
*
* SPDX - License - Identifier : GPL - 2.0 - or - later
*/
# include <QDropEvent>
# include <QMimeData>
# include <QToolTip>
2019-06-13 10:31:29 -07:00
# include <QAction>
2019-06-12 12:00:43 -07:00
# include <QInputDialog>
2019-11-03 17:12:12 +00:00
# include <QJsonDocument>
# include <QJsonObject>
2019-06-12 12:00:43 -07:00
2019-06-13 10:31:29 -07:00
# include <packet_list.h>
2019-06-12 16:35:29 -07:00
2022-01-31 19:30:09 -08:00
# include <main_application.h>
2019-06-13 10:31:29 -07:00
# include <epan/column.h>
# include <ui/recent.h>
# include <ui/preference_utils.h>
# include <ui/packet_list_utils.h>
2019-06-12 16:35:29 -07:00
# include <ui/qt/main_window.h>
2019-06-13 10:31:29 -07:00
# include <models/packet_list_model.h>
2022-02-10 15:11:43 -08:00
# include <models/pref_models.h>
2019-06-12 16:35:29 -07:00
# include <ui/qt/utils/wireshark_mime_data.h>
# include <ui/qt/widgets/packet_list_header.h>
2022-06-29 14:45:48 +02:00
PacketListHeader : : PacketListHeader ( Qt : : Orientation orientation , QWidget * parent ) :
2019-06-13 10:31:29 -07:00
QHeaderView ( orientation , parent ) ,
2022-06-29 15:46:19 +02:00
sectionIdx ( - 1 )
2019-06-12 16:35:29 -07:00
{
setAcceptDrops ( true ) ;
setSectionsMovable ( true ) ;
2020-05-02 22:36:46 +02:00
setStretchLastSection ( true ) ;
2019-06-12 16:35:29 -07:00
setDefaultAlignment ( Qt : : AlignLeft | Qt : : AlignVCenter ) ;
}
void PacketListHeader : : dragEnterEvent ( QDragEnterEvent * event )
{
2019-11-17 20:02:20 +01:00
if ( ! event | | ! event - > mimeData ( ) )
2019-06-12 16:35:29 -07:00
return ;
2019-11-17 20:02:20 +01:00
if ( event - > mimeData ( ) - > hasFormat ( WiresharkMimeData : : DisplayFilterMimeType ) & & event - > source ( ) ! = this - > parent ( ) )
2019-06-12 16:35:29 -07:00
{
2019-11-17 20:02:20 +01:00
if ( event - > source ( ) ! = this )
2019-06-12 16:35:29 -07:00
{
event - > setDropAction ( Qt : : CopyAction ) ;
event - > accept ( ) ;
} else {
event - > acceptProposedAction ( ) ;
}
}
else
QHeaderView : : dragEnterEvent ( event ) ;
}
void PacketListHeader : : dragMoveEvent ( QDragMoveEvent * event )
{
2019-11-17 20:02:20 +01:00
if ( ! event | | ! event - > mimeData ( ) )
2019-06-12 16:35:29 -07:00
return ;
2019-11-17 20:02:20 +01:00
if ( event - > mimeData ( ) - > hasFormat ( WiresharkMimeData : : DisplayFilterMimeType ) )
2019-06-12 16:35:29 -07:00
{
2019-11-17 20:02:20 +01:00
if ( event - > source ( ) ! = this )
2019-06-12 16:35:29 -07:00
{
event - > setDropAction ( Qt : : CopyAction ) ;
event - > accept ( ) ;
} else {
event - > acceptProposedAction ( ) ;
}
}
else
QHeaderView : : dragMoveEvent ( event ) ;
}
void PacketListHeader : : dropEvent ( QDropEvent * event )
{
2019-11-17 20:02:20 +01:00
if ( ! event | | ! event - > mimeData ( ) )
2019-06-12 16:35:29 -07:00
return ;
/* Moving items around */
2019-11-17 20:02:20 +01:00
if ( event - > mimeData ( ) - > hasFormat ( WiresharkMimeData : : DisplayFilterMimeType ) )
2019-11-03 17:12:12 +00:00
{
QByteArray jsonData = event - > mimeData ( ) - > data ( WiresharkMimeData : : DisplayFilterMimeType ) ;
QJsonDocument jsonDoc = QJsonDocument : : fromJson ( jsonData ) ;
2019-11-17 20:02:20 +01:00
if ( ! jsonDoc . isObject ( ) )
2019-11-03 17:12:12 +00:00
return ;
2019-06-12 16:35:29 -07:00
2019-11-03 17:12:12 +00:00
QJsonObject data = jsonDoc . object ( ) ;
2019-11-17 23:13:27 +01:00
if ( event - > source ( ) ! = this & & data . contains ( " description " ) & & data . contains ( " name " ) )
2019-06-12 16:35:29 -07:00
{
event - > setDropAction ( Qt : : CopyAction ) ;
event - > accept ( ) ;
2022-01-31 19:30:09 -08:00
MainWindow * mw = qobject_cast < MainWindow * > ( mainApp - > mainWindow ( ) ) ;
2019-11-17 20:02:20 +01:00
if ( mw )
2019-06-12 16:35:29 -07:00
{
2022-03-22 14:47:18 -07:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0 ,0)
int idx = logicalIndexAt ( event - > position ( ) . toPoint ( ) ) ;
# else
2019-06-12 16:35:29 -07:00
int idx = logicalIndexAt ( event - > pos ( ) ) ;
2022-03-22 14:47:18 -07:00
# endif
2019-11-17 23:13:27 +01:00
mw - > insertColumn ( data [ " description " ] . toString ( ) , data [ " name " ] . toString ( ) , idx ) ;
2019-06-12 16:35:29 -07:00
}
} else {
event - > acceptProposedAction ( ) ;
}
}
else
QHeaderView : : dropEvent ( event ) ;
}
void PacketListHeader : : mousePressEvent ( QMouseEvent * e )
{
2019-11-17 20:02:20 +01:00
if ( e - > button ( ) = = Qt : : LeftButton & & sectionIdx < 0 )
2019-06-12 16:35:29 -07:00
{
/* No move happening yet */
2022-03-22 14:47:18 -07:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0 ,0)
int sectIdx = logicalIndexAt ( e - > position ( ) . toPoint ( ) . x ( ) - 4 , e - > position ( ) . toPoint ( ) . y ( ) ) ;
# else
2019-06-12 16:35:29 -07:00
int sectIdx = logicalIndexAt ( e - > localPos ( ) . x ( ) - 4 , e - > localPos ( ) . y ( ) ) ;
2022-03-22 14:47:18 -07:00
# endif
2019-06-12 16:35:29 -07:00
QString headerName = model ( ) - > headerData ( sectIdx , orientation ( ) ) . toString ( ) ;
2022-03-22 14:47:18 -07:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0 ,0)
QToolTip : : showText ( e - > globalPosition ( ) . toPoint ( ) , QString ( " Width: %1 " ) . arg ( sectionSize ( sectIdx ) ) ) ;
# else
2019-06-12 16:35:29 -07:00
QToolTip : : showText ( e - > globalPos ( ) , QString ( " Width: %1 " ) . arg ( sectionSize ( sectIdx ) ) ) ;
2022-03-22 14:47:18 -07:00
# endif
2019-06-12 16:35:29 -07:00
}
QHeaderView : : mousePressEvent ( e ) ;
}
void PacketListHeader : : mouseMoveEvent ( QMouseEvent * e )
{
2019-11-17 20:02:20 +01:00
if ( e - > button ( ) = = Qt : : NoButton | | ! ( e - > buttons ( ) & Qt : : LeftButton ) )
2019-06-12 16:35:29 -07:00
{
/* no move is happening */
sectionIdx = - 1 ;
}
2019-11-17 20:02:20 +01:00
else if ( e - > buttons ( ) & Qt : : LeftButton )
2019-06-12 16:35:29 -07:00
{
/* section being moved */
2022-03-22 14:47:18 -07:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0 ,0)
int triggeredSection = logicalIndexAt ( e - > position ( ) . toPoint ( ) . x ( ) - 4 , e - > position ( ) . toPoint ( ) . y ( ) ) ;
# else
2019-06-12 16:35:29 -07:00
int triggeredSection = logicalIndexAt ( e - > localPos ( ) . x ( ) - 4 , e - > localPos ( ) . y ( ) ) ;
2022-03-22 14:47:18 -07:00
# endif
2019-06-12 16:35:29 -07:00
2019-11-17 20:02:20 +01:00
if ( sectionIdx < 0 )
2019-06-12 16:35:29 -07:00
sectionIdx = triggeredSection ;
2019-11-17 20:02:20 +01:00
else if ( sectionIdx = = triggeredSection )
2019-06-12 16:35:29 -07:00
{
/* Only run for the current moving section after a change */
QString headerName = model ( ) - > headerData ( sectionIdx , orientation ( ) ) . toString ( ) ;
2022-03-22 14:47:18 -07:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0 ,0)
2022-06-29 15:46:19 +02:00
QToolTip : : showText ( e - > globalPosition ( ) . toPoint ( ) , QString ( " Width: %1 " ) . arg ( sectionSize ( sectionIdx ) ) ) ;
2022-03-22 14:47:18 -07:00
# else
2022-06-29 15:46:19 +02:00
QToolTip : : showText ( e - > globalPos ( ) , QString ( " Width: %1 " ) . arg ( sectionSize ( sectionIdx ) ) ) ;
2022-03-22 14:47:18 -07:00
# endif
2019-06-12 16:35:29 -07:00
}
}
QHeaderView : : mouseMoveEvent ( e ) ;
}
2019-06-13 10:31:29 -07:00
void PacketListHeader : : contextMenuEvent ( QContextMenuEvent * event )
{
int sectionIdx = logicalIndexAt ( event - > pos ( ) ) ;
2022-06-29 15:46:19 +02:00
if ( sectionIdx < 0 | | sectionIdx > = prefs . num_cols )
return ;
2019-11-14 10:16:20 +01:00
char xalign = recent_get_column_xalign ( sectionIdx ) ;
2022-06-29 15:46:19 +02:00
QAction * action = nullptr ;
2019-06-13 10:31:29 -07:00
QMenu * contextMenu = new QMenu ( this ) ;
2022-09-10 16:13:43 -07:00
contextMenu - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
2019-12-20 07:57:04 +02:00
contextMenu - > setProperty ( " column " , QVariant : : fromValue ( sectionIdx ) ) ;
2019-06-13 10:31:29 -07:00
2024-09-27 11:44:43 +02:00
action = contextMenu - > addAction ( tr ( " Column Preferences… " ) ) ;
connect ( action , & QAction : : triggered , this , & PacketListHeader : : showColumnPrefs ) ;
action = contextMenu - > addAction ( tr ( " Edit Column " ) ) ;
connect ( action , & QAction : : triggered , this , & PacketListHeader : : doEditColumn ) ;
action = contextMenu - > addAction ( tr ( " Resize to Contents " ) ) ;
connect ( action , & QAction : : triggered , this , & PacketListHeader : : resizeToContent ) ;
action = contextMenu - > addAction ( tr ( " Resize Column to Width… " ) ) ;
connect ( action , & QAction : : triggered , this , & PacketListHeader : : resizeToWidth ) ;
contextMenu - > addSeparator ( ) ;
2019-06-13 10:31:29 -07:00
QActionGroup * alignmentActions = new QActionGroup ( contextMenu ) ;
2024-09-20 22:48:51 +02:00
alignmentActions - > setExclusionPolicy ( QActionGroup : : ExclusionPolicy : : ExclusiveOptional ) ;
2019-12-20 07:57:04 +02:00
alignmentActions - > setProperty ( " column " , QVariant : : fromValue ( sectionIdx ) ) ;
2019-06-13 10:31:29 -07:00
action = alignmentActions - > addAction ( tr ( " Align Left " ) ) ;
action - > setCheckable ( true ) ;
2019-11-14 10:16:20 +01:00
action - > setChecked ( xalign = = COLUMN_XALIGN_LEFT ? true : false ) ;
2019-12-20 07:57:04 +02:00
action - > setData ( QVariant : : fromValue ( COLUMN_XALIGN_LEFT ) ) ;
2019-06-13 10:31:29 -07:00
action = alignmentActions - > addAction ( tr ( " Align Center " ) ) ;
action - > setCheckable ( true ) ;
2019-11-14 10:16:20 +01:00
action - > setChecked ( xalign = = COLUMN_XALIGN_CENTER ? true : false ) ;
2019-12-20 07:57:04 +02:00
action - > setData ( QVariant : : fromValue ( COLUMN_XALIGN_CENTER ) ) ;
2019-06-13 10:31:29 -07:00
action = alignmentActions - > addAction ( tr ( " Align Right " ) ) ;
action - > setCheckable ( true ) ;
2019-11-14 10:16:20 +01:00
action - > setChecked ( xalign = = COLUMN_XALIGN_RIGHT ? true : false ) ;
2019-12-20 07:57:04 +02:00
action - > setData ( QVariant : : fromValue ( COLUMN_XALIGN_RIGHT ) ) ;
2019-06-13 10:31:29 -07:00
connect ( alignmentActions , & QActionGroup : : triggered , this , & PacketListHeader : : setAlignment ) ;
contextMenu - > addActions ( alignmentActions - > actions ( ) ) ;
contextMenu - > addSeparator ( ) ;
2024-09-11 14:26:14 +02:00
bool canDisplayStrings = model ( ) - > headerData ( sectionIdx , Qt : : Horizontal , PacketListModel : : HEADER_CAN_DISPLAY_STRINGS ) . toBool ( ) ;
bool canDisplayDetails = model ( ) - > headerData ( sectionIdx , Qt : : Horizontal , PacketListModel : : HEADER_CAN_DISPLAY_DETAILS ) . toBool ( ) ;
QString displayToolTip = tr ( " <html>Values will show the raw values for fields.<p>Strings will show human-readable strings instead of raw values for fields. Only applicable to custom columns with fields that have value strings and custom columns which can be resolved to strings.<p>Details will show the values using the same format as in Packet Details. Only applicable to custom columns.</html> " ) ;
QActionGroup * displayActions = new QActionGroup ( contextMenu ) ;
displayActions - > setExclusive ( true ) ;
displayActions - > setProperty ( " column " , QVariant : : fromValue ( sectionIdx ) ) ;
action = displayActions - > addAction ( tr ( " Display as Values " ) ) ;
action - > setEnabled ( canDisplayStrings | | canDisplayDetails ) ;
2022-06-27 20:26:08 -04:00
action - > setCheckable ( true ) ;
2024-09-11 14:26:14 +02:00
action - > setChecked ( ! action - > isEnabled ( ) | | get_column_display_format ( sectionIdx ) = = COLUMN_DISPLAY_VALUES ) ;
action - > setData ( QVariant : : fromValue ( COLUMN_DISPLAY_VALUES ) ) ;
action - > setToolTip ( displayToolTip ) ;
action = displayActions - > addAction ( tr ( " Display as Strings " ) ) ;
action - > setEnabled ( canDisplayStrings ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( action - > isEnabled ( ) & & ( get_column_display_format ( sectionIdx ) = = COLUMN_DISPLAY_STRINGS ) ) ;
action - > setData ( QVariant : : fromValue ( COLUMN_DISPLAY_STRINGS ) ) ;
action - > setToolTip ( displayToolTip ) ;
action = displayActions - > addAction ( tr ( " Display as packet Details " ) ) ;
action - > setEnabled ( canDisplayDetails ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( action - > isEnabled ( ) & & ( get_column_display_format ( sectionIdx ) = = COLUMN_DISPLAY_DETAILS ) ) ;
action - > setData ( QVariant : : fromValue ( COLUMN_DISPLAY_DETAILS ) ) ;
action - > setToolTip ( displayToolTip ) ;
connect ( displayActions , & QActionGroup : : triggered , this , & PacketListHeader : : setDisplayFormat ) ;
2019-06-13 10:31:29 -07:00
2024-09-11 14:26:14 +02:00
contextMenu - > addActions ( displayActions - > actions ( ) ) ;
2019-06-13 10:31:29 -07:00
contextMenu - > addSeparator ( ) ;
for ( int cnt = 0 ; cnt < prefs . num_cols ; cnt + + ) {
2019-11-14 10:34:27 +01:00
QString title ( get_column_title ( cnt ) ) ;
2020-01-09 12:12:57 +01:00
QString detail ;
2019-11-14 10:34:27 +01:00
if ( get_column_format ( cnt ) = = COL_CUSTOM ) {
2020-01-09 12:12:57 +01:00
detail = get_column_custom_fields ( cnt ) ;
2019-11-25 10:48:10 +01:00
} else {
2020-01-09 12:12:57 +01:00
detail = col_format_desc ( get_column_format ( cnt ) ) ;
2019-11-14 10:34:27 +01:00
}
2020-01-09 12:12:57 +01:00
2023-05-07 23:34:07 +02:00
if ( prefs . gui_packet_header_column_definition )
2020-01-09 12:12:57 +01:00
title . append ( QString ( " \t %1 " ) . arg ( detail ) ) ;
2019-11-14 10:34:27 +01:00
QAction * action = new QAction ( title , this ) ;
2020-01-09 12:12:57 +01:00
action - > setToolTip ( detail ) ;
2019-06-13 10:31:29 -07:00
action - > setCheckable ( true ) ;
action - > setChecked ( get_column_visible ( cnt ) ) ;
action - > setData ( QVariant : : fromValue ( cnt ) ) ;
connect ( action , & QAction : : triggered , this , & PacketListHeader : : columnVisibilityTriggered ) ;
contextMenu - > addAction ( action ) ;
}
2020-01-09 12:12:57 +01:00
contextMenu - > setToolTipsVisible ( true ) ;
2019-06-13 10:31:29 -07:00
contextMenu - > addSeparator ( ) ;
action = contextMenu - > addAction ( tr ( " Remove this Column " ) ) ;
action - > setEnabled ( sectionIdx > = 0 & & count ( ) > 2 ) ;
connect ( action , & QAction : : triggered , this , & PacketListHeader : : removeColumn ) ;
contextMenu - > popup ( viewport ( ) - > mapToGlobal ( event - > pos ( ) ) ) ;
}
void PacketListHeader : : columnVisibilityTriggered ( )
{
QAction * ha = qobject_cast < QAction * > ( sender ( ) ) ;
if ( ! ha ) return ;
int col = ha - > data ( ) . toInt ( ) ;
set_column_visible ( col , ha - > isChecked ( ) ) ;
2022-06-29 15:46:19 +02:00
setSectionHidden ( col , ha - > isChecked ( ) ? false : true ) ;
2019-06-13 10:31:29 -07:00
if ( ha - > isChecked ( ) )
emit resetColumnWidth ( col ) ;
prefs_main_write ( ) ;
}
void PacketListHeader : : setAlignment ( QAction * action )
{
if ( ! action )
return ;
QActionGroup * group = action - > actionGroup ( ) ;
if ( ! group )
return ;
int section = group - > property ( " column " ) . toInt ( ) ;
2019-11-17 20:02:20 +01:00
if ( section > = 0 )
2019-06-13 10:31:29 -07:00
{
QChar data = action - > data ( ) . toChar ( ) ;
recent_set_column_xalign ( section , action - > isChecked ( ) ? data . toLatin1 ( ) : COLUMN_XALIGN_DEFAULT ) ;
emit updatePackets ( false ) ;
}
}
void PacketListHeader : : showColumnPrefs ( )
{
2019-08-09 11:28:04 +02:00
emit showColumnPreferences ( PrefsModel : : typeToString ( PrefsModel : : Columns ) ) ;
2019-06-13 10:31:29 -07:00
}
void PacketListHeader : : doEditColumn ( )
{
QAction * action = qobject_cast < QAction * > ( sender ( ) ) ;
if ( ! action )
return ;
QMenu * menu = qobject_cast < QMenu * > ( action - > parent ( ) ) ;
if ( ! menu )
return ;
int section = menu - > property ( " column " ) . toInt ( ) ;
emit editColumn ( section ) ;
}
2024-09-11 14:26:14 +02:00
void PacketListHeader : : setDisplayFormat ( QAction * action )
2019-06-13 10:31:29 -07:00
{
2019-08-19 18:36:55 +02:00
if ( ! action )
return ;
2024-09-11 14:26:14 +02:00
QActionGroup * group = action - > actionGroup ( ) ;
if ( ! group )
2019-08-19 18:36:55 +02:00
return ;
2024-09-11 14:26:14 +02:00
int section = group - > property ( " column " ) . toInt ( ) ;
QChar data = action - > data ( ) . toChar ( ) ;
2019-06-13 10:31:29 -07:00
2024-09-11 14:26:14 +02:00
set_column_display_format ( section , action - > isChecked ( ) ? data . toLatin1 ( ) : COLUMN_DISPLAY_VALUES ) ;
2019-06-13 10:31:29 -07:00
prefs_main_write ( ) ;
emit updatePackets ( true ) ;
}
void PacketListHeader : : resizeToContent ( )
{
QAction * action = qobject_cast < QAction * > ( sender ( ) ) ;
2019-08-19 18:36:55 +02:00
if ( ! action )
return ;
2019-06-13 10:31:29 -07:00
QMenu * menu = qobject_cast < QMenu * > ( action - > parent ( ) ) ;
2019-08-19 18:36:55 +02:00
if ( ! menu )
2019-06-13 10:31:29 -07:00
return ;
int section = menu - > property ( " column " ) . toInt ( ) ;
PacketList * packetList = qobject_cast < PacketList * > ( parent ( ) ) ;
2019-11-17 20:02:20 +01:00
if ( packetList )
2019-06-13 10:31:29 -07:00
packetList - > resizeColumnToContents ( section ) ;
}
void PacketListHeader : : removeColumn ( )
{
QAction * action = qobject_cast < QAction * > ( sender ( ) ) ;
2019-08-19 18:36:55 +02:00
if ( ! action )
return ;
2019-06-13 10:31:29 -07:00
QMenu * menu = qobject_cast < QMenu * > ( action - > parent ( ) ) ;
2019-08-19 18:36:55 +02:00
if ( ! menu )
2019-06-13 10:31:29 -07:00
return ;
int section = menu - > property ( " column " ) . toInt ( ) ;
if ( count ( ) > 2 ) {
column_prefs_remove_nth ( section ) ;
emit columnsChanged ( ) ;
prefs_main_write ( ) ;
}
}
2019-06-12 12:00:43 -07:00
void PacketListHeader : : resizeToWidth ( )
{
QAction * action = qobject_cast < QAction * > ( sender ( ) ) ;
2019-08-19 18:36:55 +02:00
if ( ! action )
return ;
2019-06-12 12:00:43 -07:00
QMenu * menu = qobject_cast < QMenu * > ( action - > parent ( ) ) ;
2019-08-19 18:36:55 +02:00
if ( ! menu )
2019-06-12 12:00:43 -07:00
return ;
bool ok = false ;
int width = - 1 ;
int section = menu - > property ( " column " ) . toInt ( ) ;
QString headerName = model ( ) - > headerData ( section , orientation ( ) ) . toString ( ) ;
width = QInputDialog : : getInt ( this , tr ( " Column %1 " ) . arg ( headerName ) , tr ( " Width: " ) ,
sectionSize ( section ) , 0 , 1000 , 1 , & ok ) ;
if ( ok )
resizeSection ( section , width ) ;
}