forked from osmocom/wireshark
TCP: Overriding of the automatic SEQ Analysis
This commit is contained in:
parent
891716800b
commit
6759377b93
|
@ -95,6 +95,18 @@ static gboolean tcp_check_checksum = FALSE;
|
||||||
WindowScaling_14
|
WindowScaling_14
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Analysis overriding values to be used when not satisfied by the automatic
|
||||||
|
* result. (Accessed through preferences but not stored as a preference)
|
||||||
|
*/
|
||||||
|
enum override_analysis_value {
|
||||||
|
OverrideAnalysis_0=0,
|
||||||
|
OverrideAnalysis_1,
|
||||||
|
OverrideAnalysis_2,
|
||||||
|
OverrideAnalysis_3,
|
||||||
|
OverrideAnalysis_4
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Using enum instead of boolean make API easier
|
* Using enum instead of boolean make API easier
|
||||||
*/
|
*/
|
||||||
|
@ -122,6 +134,8 @@ static const value_string mp_tcprst_reasons[] = {
|
||||||
|
|
||||||
static gint tcp_default_window_scaling = (gint)WindowScaling_NotKnown;
|
static gint tcp_default_window_scaling = (gint)WindowScaling_NotKnown;
|
||||||
|
|
||||||
|
static gint tcp_default_override_analysis = (gint)OverrideAnalysis_0;
|
||||||
|
|
||||||
static int proto_tcp = -1;
|
static int proto_tcp = -1;
|
||||||
static int proto_ip = -1;
|
static int proto_ip = -1;
|
||||||
static int proto_icmp = -1;
|
static int proto_icmp = -1;
|
||||||
|
@ -2108,7 +2122,7 @@ tcp_analyze_get_acked_struct(guint32 frame, guint32 seq, guint32 ack, gboolean c
|
||||||
* Guide: docbook/wsug_src/WSUG_chapter_advanced.adoc
|
* Guide: docbook/wsug_src/WSUG_chapter_advanced.adoc
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
tcp_analyze_sequence_number(packet_info *pinfo, guint32 seq, guint32 ack, guint32 seglen, guint16 flags, guint32 window, struct tcp_analysis *tcpd)
|
tcp_analyze_sequence_number(packet_info *pinfo, guint32 seq, guint32 ack, guint32 seglen, guint16 flags, guint32 window, struct tcp_analysis *tcpd, struct tcp_per_packet_data_t *tcppd)
|
||||||
{
|
{
|
||||||
tcp_unacked_t *ual=NULL;
|
tcp_unacked_t *ual=NULL;
|
||||||
tcp_unacked_t *prevual=NULL;
|
tcp_unacked_t *prevual=NULL;
|
||||||
|
@ -2534,6 +2548,53 @@ finished_fwd:
|
||||||
|
|
||||||
finished_checking_retransmission_type:
|
finished_checking_retransmission_type:
|
||||||
|
|
||||||
|
/* Override the TCP sequence analysis with the value given
|
||||||
|
* manually by the user. This only applies to flagged packets.
|
||||||
|
*/
|
||||||
|
if(tcppd && tcpd->ta &&
|
||||||
|
(tcppd->tcp_snd_manual_analysis>0) &&
|
||||||
|
(tcpd->ta->flags & TCP_A_RETRANSMISSION ||
|
||||||
|
tcpd->ta->flags & TCP_A_OUT_OF_ORDER ||
|
||||||
|
tcpd->ta->flags & TCP_A_FAST_RETRANSMISSION ||
|
||||||
|
tcpd->ta->flags & TCP_A_SPURIOUS_RETRANSMISSION)) {
|
||||||
|
|
||||||
|
/* clean flags set during the automatic analysis */
|
||||||
|
tcpd->ta->flags &= ~(TCP_A_RETRANSMISSION|
|
||||||
|
TCP_A_OUT_OF_ORDER|
|
||||||
|
TCP_A_FAST_RETRANSMISSION|
|
||||||
|
TCP_A_SPURIOUS_RETRANSMISSION);
|
||||||
|
|
||||||
|
/* set the corresponding flag chosen by the user */
|
||||||
|
switch(tcppd->tcp_snd_manual_analysis) {
|
||||||
|
case 0:
|
||||||
|
/* the user asked for an empty overriding, which
|
||||||
|
* means removing any previous value, thus restoring
|
||||||
|
* the automatic analysis.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
tcpd->ta->flags|=TCP_A_OUT_OF_ORDER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
tcpd->ta->flags|=TCP_A_RETRANSMISSION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
tcpd->ta->flags|=TCP_A_FAST_RETRANSMISSION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
tcpd->ta->flags|=TCP_A_SPURIOUS_RETRANSMISSION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* there is no expected default case */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nextseq = seq+seglen;
|
nextseq = seq+seglen;
|
||||||
if ((seglen || flags&(TH_SYN|TH_FIN)) && tcpd->fwd->tcp_analyze_seq_info->segment_count < TCP_MAX_UNACKED_SEGMENTS) {
|
if ((seglen || flags&(TH_SYN|TH_FIN)) && tcpd->fwd->tcp_analyze_seq_info->segment_count < TCP_MAX_UNACKED_SEGMENTS) {
|
||||||
/* Add this new sequence number to the fwd list. But only if there
|
/* Add this new sequence number to the fwd list. But only if there
|
||||||
|
@ -7695,6 +7756,12 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
||||||
tcp_calculate_timestamps(pinfo, tcpd, tcppd);
|
tcp_calculate_timestamps(pinfo, tcpd, tcppd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* is there any manual analysis waiting ? */
|
||||||
|
if(pinfo->fd->tcp_snd_manual_analysis > 0) {
|
||||||
|
tcppd = (struct tcp_per_packet_data_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_tcp, pinfo->curr_layer_num);
|
||||||
|
tcppd->tcp_snd_manual_analysis = pinfo->fd->tcp_snd_manual_analysis;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've been handed an IP fragment, we don't know how big the TCP
|
* If we've been handed an IP fragment, we don't know how big the TCP
|
||||||
* segment is, so don't do anything that requires that we know that.
|
* segment is, so don't do anything that requires that we know that.
|
||||||
|
@ -7731,7 +7798,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
||||||
/* handle TCP seq# analysis parse all new segments we see */
|
/* handle TCP seq# analysis parse all new segments we see */
|
||||||
if(tcp_analyze_seq) {
|
if(tcp_analyze_seq) {
|
||||||
if(!(pinfo->fd->visited)) {
|
if(!(pinfo->fd->visited)) {
|
||||||
tcp_analyze_sequence_number(pinfo, tcph->th_seq, tcph->th_ack, tcph->th_seglen, tcph->th_flags, tcph->th_win, tcpd);
|
tcp_analyze_sequence_number(pinfo, tcph->th_seq, tcph->th_ack, tcph->th_seglen, tcph->th_flags, tcph->th_win, tcpd, tcppd);
|
||||||
}
|
}
|
||||||
if(tcpd && tcp_relative_seq) {
|
if(tcpd && tcp_relative_seq) {
|
||||||
(tcph->th_seq) -= tcpd->fwd->base_seq;
|
(tcph->th_seq) -= tcpd->fwd->base_seq;
|
||||||
|
@ -9351,6 +9418,15 @@ proto_register_tcp(void)
|
||||||
{NULL, NULL, -1}
|
{NULL, NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const enum_val_t override_analysis_vals[] = {
|
||||||
|
{"0", "0 (none)", OverrideAnalysis_0},
|
||||||
|
{"1", "1 (Out-of-Order)", OverrideAnalysis_1},
|
||||||
|
{"2", "2 (Retransmission)", OverrideAnalysis_2},
|
||||||
|
{"3", "3 (Fast Retransmission)", OverrideAnalysis_3},
|
||||||
|
{"4", "4 (Spurious Retransmission)",OverrideAnalysis_4},
|
||||||
|
{NULL, NULL, -1}
|
||||||
|
};
|
||||||
|
|
||||||
static ei_register_info ei[] = {
|
static ei_register_info ei[] = {
|
||||||
{ &ei_tcp_opt_len_invalid, { "tcp.option.len.invalid", PI_SEQUENCE, PI_NOTE, "Invalid length for option", EXPFILL }},
|
{ &ei_tcp_opt_len_invalid, { "tcp.option.len.invalid", PI_SEQUENCE, PI_NOTE, "Invalid length for option", EXPFILL }},
|
||||||
{ &ei_tcp_analysis_retransmission, { "tcp.analysis.retransmission", PI_SEQUENCE, PI_NOTE, "This frame is a (suspected) retransmission", EXPFILL }},
|
{ &ei_tcp_analysis_retransmission, { "tcp.analysis.retransmission", PI_SEQUENCE, PI_NOTE, "This frame is a (suspected) retransmission", EXPFILL }},
|
||||||
|
@ -9556,6 +9632,12 @@ proto_register_tcp(void)
|
||||||
"Make the TCP dissector use relative sequence numbers instead of absolute ones. "
|
"Make the TCP dissector use relative sequence numbers instead of absolute ones. "
|
||||||
"To use this option you must also enable \"Analyze TCP sequence numbers\". ",
|
"To use this option you must also enable \"Analyze TCP sequence numbers\". ",
|
||||||
&tcp_relative_seq);
|
&tcp_relative_seq);
|
||||||
|
|
||||||
|
prefs_register_custom_preference_TCP_Analysis(tcp_module, "default_override_analysis",
|
||||||
|
"Force interpretation to selected packet(s)",
|
||||||
|
"Override the default analysis with this value for the selected packet",
|
||||||
|
&tcp_default_override_analysis, override_analysis_vals, FALSE);
|
||||||
|
|
||||||
prefs_register_enum_preference(tcp_module, "default_window_scaling",
|
prefs_register_enum_preference(tcp_module, "default_window_scaling",
|
||||||
"Scaling factor to use when not available from capture",
|
"Scaling factor to use when not available from capture",
|
||||||
"Make the TCP dissector use this scaling factor for streams where the signalled scaling factor "
|
"Make the TCP dissector use this scaling factor for streams where the signalled scaling factor "
|
||||||
|
|
|
@ -506,6 +506,7 @@ struct tcp_analysis {
|
||||||
*/
|
*/
|
||||||
struct tcp_per_packet_data_t {
|
struct tcp_per_packet_data_t {
|
||||||
nstime_t ts_del;
|
nstime_t ts_del;
|
||||||
|
guint8 tcp_snd_manual_analysis;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Structure that keeps per packet data. Some operations are cpu-intensive and are
|
/* Structure that keeps per packet data. Some operations are cpu-intensive and are
|
||||||
|
|
|
@ -167,6 +167,7 @@ frame_data_init(frame_data *fdata, guint32 num, const wtap_rec *rec,
|
||||||
fdata->ref_time = 0;
|
fdata->ref_time = 0;
|
||||||
fdata->ignored = 0;
|
fdata->ignored = 0;
|
||||||
fdata->has_ts = (rec->presence_flags & WTAP_HAS_TS) ? 1 : 0;
|
fdata->has_ts = (rec->presence_flags & WTAP_HAS_TS) ? 1 : 0;
|
||||||
|
fdata->tcp_snd_manual_analysis = 0;
|
||||||
switch (rec->rec_type) {
|
switch (rec->rec_type) {
|
||||||
|
|
||||||
case REC_TYPE_PACKET:
|
case REC_TYPE_PACKET:
|
||||||
|
|
|
@ -91,6 +91,7 @@ typedef struct _frame_data {
|
||||||
nstime_t shift_offset; /**< How much the abs_tm of the frame is shifted */
|
nstime_t shift_offset; /**< How much the abs_tm of the frame is shifted */
|
||||||
guint32 frame_ref_num; /**< Previous reference frame (0 if this is one) */
|
guint32 frame_ref_num; /**< Previous reference frame (0 if this is one) */
|
||||||
guint32 prev_dis_num; /**< Previous displayed frame (0 if first one) */
|
guint32 prev_dis_num; /**< Previous displayed frame (0 if first one) */
|
||||||
|
guint8 tcp_snd_manual_analysis; /**< TCP SEQ Analysis Overriding, 0 = none, 1 = OOO, 2 = RET , 3 = Fast RET, 4 = Spurious RET */
|
||||||
} frame_data;
|
} frame_data;
|
||||||
DIAG_ON_PEDANTIC
|
DIAG_ON_PEDANTIC
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,11 @@ struct pref_custom_cbs {
|
||||||
#define PREF_DECODE_AS_RANGE (1u << 13) /* use and not as a generic protocol preference */
|
#define PREF_DECODE_AS_RANGE (1u << 13) /* use and not as a generic protocol preference */
|
||||||
#define PREF_OPEN_FILENAME (1u << 14)
|
#define PREF_OPEN_FILENAME (1u << 14)
|
||||||
#define PREF_PASSWORD (1u << 15) /* like string, but never saved to prefs file */
|
#define PREF_PASSWORD (1u << 15) /* like string, but never saved to prefs file */
|
||||||
|
/**
|
||||||
|
* Dedicated to TCP PROTOCOL for handling manual SEQ interpretation,
|
||||||
|
* and allow users manage the sender traffic ambiguities
|
||||||
|
*/
|
||||||
|
#define PREF_PROTO_TCP_SNDAMB_ENUM (1u << 16)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GUI_ALL,
|
GUI_ALL,
|
||||||
|
|
43
epan/prefs.c
43
epan/prefs.c
|
@ -354,6 +354,9 @@ free_pref(gpointer data, gpointer user_data _U_)
|
||||||
pref->stashed_val.boolval = TRUE;
|
pref->stashed_val.boolval = TRUE;
|
||||||
pref->custom_cbs.free_cb(pref);
|
pref->custom_cbs.free_cb(pref);
|
||||||
break;
|
break;
|
||||||
|
/* non-generic preferences */
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(pref);
|
g_free(pref);
|
||||||
|
@ -1884,6 +1887,28 @@ prefs_register_custom_preference(module_t *module, const char *name,
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a dedicated TCP preference for SEQ analysis overriding.
|
||||||
|
* We are reusing the data structure from enum preference, as they are
|
||||||
|
* similar in practice.
|
||||||
|
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
prefs_register_custom_preference_TCP_Analysis(module_t *module, const char *name,
|
||||||
|
const char *title, const char *description,
|
||||||
|
gint *var, const enum_val_t *enumvals,
|
||||||
|
gboolean radio_buttons)
|
||||||
|
{
|
||||||
|
pref_t *preference;
|
||||||
|
|
||||||
|
preference = register_preference(module, name, title, description,
|
||||||
|
PREF_PROTO_TCP_SNDAMB_ENUM);
|
||||||
|
preference->varp.enump = var;
|
||||||
|
preference->default_val.enumval = *var;
|
||||||
|
preference->info.enum_info.enumvals = enumvals;
|
||||||
|
preference->info.enum_info.radio_buttons = radio_buttons;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register a (internal) "Decode As" preference with a ranged value.
|
* Register a (internal) "Decode As" preference with a ranged value.
|
||||||
*/
|
*/
|
||||||
|
@ -2023,6 +2048,7 @@ pref_stash(pref_t *pref, gpointer unused _U_)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
pref->stashed_val.enumval = *pref->varp.enump;
|
pref->stashed_val.enumval = *pref->varp.enump;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2112,6 +2138,15 @@ pref_unstash(pref_t *pref, gpointer unstash_data_p)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
|
/*if (*pref->varp.enump != pref->stashed_val.enumval) {
|
||||||
|
unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
|
||||||
|
//unstash_data->module->prefs_changed_flags = 1;
|
||||||
|
*pref->varp.enump = pref->stashed_val.enumval;
|
||||||
|
}*/
|
||||||
|
unstash_data->module->prefs_changed_flags = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case PREF_STRING:
|
case PREF_STRING:
|
||||||
case PREF_SAVE_FILENAME:
|
case PREF_SAVE_FILENAME:
|
||||||
case PREF_OPEN_FILENAME:
|
case PREF_OPEN_FILENAME:
|
||||||
|
@ -2216,6 +2251,7 @@ reset_stashed_pref(pref_t *pref) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
pref->stashed_val.enumval = pref->default_val.enumval;
|
pref->stashed_val.enumval = pref->default_val.enumval;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2262,6 +2298,7 @@ pref_clean_stash(pref_t *pref, gpointer unused _U_)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_STRING:
|
case PREF_STRING:
|
||||||
|
@ -4257,6 +4294,7 @@ reset_pref(pref_t *pref)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
/*
|
/*
|
||||||
* For now, we save the "description" value, so that if we
|
* For now, we save the "description" value, so that if we
|
||||||
* save the preferences older versions of Wireshark can at
|
* save the preferences older versions of Wireshark can at
|
||||||
|
@ -6037,6 +6075,7 @@ set_pref(gchar *pref_name, const gchar *value, void *private_data _U_,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
/* XXX - give an error if it doesn't match? */
|
/* XXX - give an error if it doesn't match? */
|
||||||
enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
|
enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
|
||||||
*pref->varp.enump);
|
*pref->varp.enump);
|
||||||
|
@ -6197,6 +6236,7 @@ prefs_pref_type_name(pref_t *pref)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
type_name = "Choice";
|
type_name = "Choice";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -6332,6 +6372,7 @@ prefs_pref_type_description(pref_t *pref)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
{
|
{
|
||||||
const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
|
const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
|
||||||
GString *enum_str = g_string_new("One of: ");
|
GString *enum_str = g_string_new("One of: ");
|
||||||
|
@ -6433,6 +6474,7 @@ prefs_pref_is_default(pref_t *pref)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
if (pref->default_val.enumval == *pref->varp.enump)
|
if (pref->default_val.enumval == *pref->varp.enump)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -6538,6 +6580,7 @@ prefs_pref_to_str(pref_t *pref, pref_source_t source) {
|
||||||
return g_strdup((*(gboolean *) valp) ? "TRUE" : "FALSE");
|
return g_strdup((*(gboolean *) valp) ? "TRUE" : "FALSE");
|
||||||
|
|
||||||
case PREF_ENUM:
|
case PREF_ENUM:
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
{
|
{
|
||||||
gint pref_enumval = *(gint *) valp;
|
gint pref_enumval = *(gint *) valp;
|
||||||
/*
|
/*
|
||||||
|
|
24
epan/prefs.h
24
epan/prefs.h
|
@ -776,6 +776,30 @@ WS_DLL_PUBLIC void prefs_register_password_preference(module_t *module, const ch
|
||||||
WS_DLL_PUBLIC void prefs_register_obsolete_preference(module_t *module,
|
WS_DLL_PUBLIC void prefs_register_obsolete_preference(module_t *module,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a preference with an enumerated value.
|
||||||
|
* @param module the preferences module returned by prefs_register_protocol() or
|
||||||
|
* prefs_register_protocol_subtree()
|
||||||
|
* @param name the preference's identifier. This is appended to the name of the
|
||||||
|
* protocol, with a "." between them, to create a unique identifier.
|
||||||
|
* The identifier should not include the protocol name, as the name in
|
||||||
|
* the preference file will already have it. Make sure that
|
||||||
|
* only lower-case ASCII letters, numbers, underscores and
|
||||||
|
* dots appear in the preference name.
|
||||||
|
* @param title Field's title in the preferences dialog
|
||||||
|
* @param description description to include in the preferences file
|
||||||
|
* and shown as tooltip in the GUI, or NULL
|
||||||
|
* @param var pointer to the storage location that is updated when the
|
||||||
|
* field is changed in the preference dialog box
|
||||||
|
* @param enumvals a null-terminated array of enum_val_t structures
|
||||||
|
* @param radio_buttons TRUE if the field is to be displayed in the
|
||||||
|
* preferences dialog as a set of radio buttons,
|
||||||
|
* FALSE if it is to be displayed as an option menu
|
||||||
|
*/
|
||||||
|
WS_DLL_PUBLIC void prefs_register_custom_preference_TCP_Analysis(module_t *module, const char *name,
|
||||||
|
const char *title, const char *description, gint *var,
|
||||||
|
const enum_val_t *enumvals, gboolean radio_buttons);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a preference that affects fields change. This works for bool, enum,
|
* Mark a preference that affects fields change. This works for bool, enum,
|
||||||
* int, string (containing filename), range preferences. UAT is not included,
|
* int, string (containing filename), range preferences. UAT is not included,
|
||||||
|
|
|
@ -2856,11 +2856,3 @@ void LograyMainWindow::setMwFileName(QString fileName)
|
||||||
mwFileName_ = fileName;
|
mwFileName_ = fileName;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_data * LograyMainWindow::frameDataForRow(int row) const
|
|
||||||
{
|
|
||||||
if (packet_list_)
|
|
||||||
return packet_list_->getFDataForRow(row);
|
|
||||||
|
|
||||||
return Q_NULLPTR;
|
|
||||||
}
|
|
||||||
|
|
|
@ -124,8 +124,6 @@ public:
|
||||||
QString getMwFileName();
|
QString getMwFileName();
|
||||||
void setMwFileName(QString fileName);
|
void setMwFileName(QString fileName);
|
||||||
|
|
||||||
frame_data * frameDataForRow(int row) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||||
virtual bool event(QEvent *event);
|
virtual bool event(QEvent *event);
|
||||||
|
|
|
@ -47,6 +47,14 @@ QList<int> MainWindow::selectedRows(bool useFrameNum)
|
||||||
return QList<int>();
|
return QList<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame_data* MainWindow::frameDataForRow(int row) const
|
||||||
|
{
|
||||||
|
if (packet_list_)
|
||||||
|
return packet_list_->getFDataForRow(row);
|
||||||
|
|
||||||
|
return Q_NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::insertColumn(QString name, QString abbrev, gint pos)
|
void MainWindow::insertColumn(QString name, QString abbrev, gint pos)
|
||||||
{
|
{
|
||||||
gint colnr = 0;
|
gint colnr = 0;
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
|
|
||||||
#include <epan/prefs.h>
|
#include <epan/prefs.h>
|
||||||
#include <epan/stat_groups.h>
|
#include <epan/stat_groups.h>
|
||||||
|
#include <epan/frame_data.h>
|
||||||
|
|
||||||
|
// frame_data also available with this include in the original wireshark_main_window code
|
||||||
|
//#include "follow_stream_dialog.h"
|
||||||
|
|
||||||
|
|
||||||
#include "filter_action.h"
|
#include "filter_action.h"
|
||||||
|
|
||||||
|
@ -40,6 +45,7 @@ public:
|
||||||
QList<int> selectedRows(bool useFrameNum = false);
|
QList<int> selectedRows(bool useFrameNum = false);
|
||||||
void insertColumn(QString name, QString abbrev, gint pos = -1);
|
void insertColumn(QString name, QString abbrev, gint pos = -1);
|
||||||
void gotoFrame(int packet_num);
|
void gotoFrame(int packet_num);
|
||||||
|
frame_data* frameDataForRow(int) const;
|
||||||
|
|
||||||
QString getFilter();
|
QString getFilter();
|
||||||
MainStatusBar *statusBar();
|
MainStatusBar *statusBar();
|
||||||
|
|
|
@ -172,6 +172,16 @@ void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
||||||
other_pen.setStyle(Qt::DashLine);
|
other_pen.setStyle(Qt::DashLine);
|
||||||
painter->setPen(other_pen);
|
painter->setPen(other_pen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// analysis overriding mark (three horizontal lines)
|
||||||
|
if(fd->tcp_snd_manual_analysis) {
|
||||||
|
int wbound = (en_w - 1) / 2;
|
||||||
|
|
||||||
|
painter->drawLine(-wbound, 1, wbound, 1);
|
||||||
|
painter->drawLine(-wbound, height / 2, wbound, height / 2);
|
||||||
|
painter->drawLine(-wbound, height - 2, wbound, height - 2);
|
||||||
|
}
|
||||||
|
|
||||||
painter->drawLine(0, 0, 0, height);
|
painter->drawLine(0, 0, 0, height);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
break;
|
break;
|
||||||
|
@ -184,6 +194,18 @@ void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
||||||
QPoint(0, 0)
|
QPoint(0, 0)
|
||||||
};
|
};
|
||||||
painter->drawPolyline(end_line, 3);
|
painter->drawPolyline(end_line, 3);
|
||||||
|
/* analysis overriding on the last packet of the conversation,
|
||||||
|
* we mark it with an additional horizontal line only.
|
||||||
|
* See issue 10725 for example.
|
||||||
|
*/
|
||||||
|
// analysis overriding mark (three horizontal lines)
|
||||||
|
if(fd->tcp_snd_manual_analysis) {
|
||||||
|
int wbound = (en_w - 1) / 2;
|
||||||
|
|
||||||
|
painter->drawLine(-wbound, 1, wbound, 1);
|
||||||
|
painter->drawLine(-wbound, height / 2, wbound, height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <ui/qt/utils/qt_ui_utils.h>
|
#include <ui/qt/utils/qt_ui_utils.h>
|
||||||
#include "uat_dialog.h"
|
#include "uat_dialog.h"
|
||||||
#include "main_application.h"
|
#include "main_application.h"
|
||||||
|
#include "ui/qt/main_window.h"
|
||||||
|
|
||||||
#include <ui/qt/utils/variant_pointer.h>
|
#include <ui/qt/utils/variant_pointer.h>
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include <QMainWindow>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
@ -240,6 +242,50 @@ pref_show(pref_t *pref, gpointer user_data)
|
||||||
// color picker similar to the Font and Colors prefs.
|
// color picker similar to the Font and Colors prefs.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
|
{
|
||||||
|
const enum_val_t *ev;
|
||||||
|
ev = prefs_get_enumvals(pref);
|
||||||
|
if (!ev || !ev->description)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (prefs_get_enum_radiobuttons(pref)) {
|
||||||
|
QLabel *label = new QLabel(prefs_get_title(pref));
|
||||||
|
label->setToolTip(tooltip);
|
||||||
|
vb->addWidget(label);
|
||||||
|
QButtonGroup *enum_bg = new QButtonGroup(vb);
|
||||||
|
while (ev->description) {
|
||||||
|
QRadioButton *enum_rb = new QRadioButton(title_to_shortcut(ev->description));
|
||||||
|
enum_rb->setToolTip(tooltip);
|
||||||
|
QStyleOption style_opt;
|
||||||
|
enum_rb->setProperty(pref_prop_, VariantPointer<pref_t>::asQVariant(pref));
|
||||||
|
enum_rb->setStyleSheet(QString(
|
||||||
|
"QRadioButton {"
|
||||||
|
" margin-left: %1px;"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
.arg(enum_rb->style()->subElementRect(QStyle::SE_CheckBoxContents, &style_opt).left()));
|
||||||
|
enum_bg->addButton(enum_rb, ev->value);
|
||||||
|
vb->addWidget(enum_rb);
|
||||||
|
ev++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QHBoxLayout *hb = new QHBoxLayout();
|
||||||
|
QComboBox *enum_cb = new QComboBox();
|
||||||
|
enum_cb->setToolTip(tooltip);
|
||||||
|
enum_cb->setProperty(pref_prop_, VariantPointer<pref_t>::asQVariant(pref));
|
||||||
|
for (ev = prefs_get_enumvals(pref); ev && ev->description; ev++) {
|
||||||
|
enum_cb->addItem(ev->description, QVariant(ev->value));
|
||||||
|
}
|
||||||
|
QLabel * lbl = new QLabel(prefs_get_title(pref));
|
||||||
|
lbl->setToolTip(tooltip);
|
||||||
|
hb->addWidget(lbl);
|
||||||
|
hb->addWidget(enum_cb);
|
||||||
|
hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||||||
|
vb->addLayout(hb);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -326,6 +372,16 @@ ModulePreferencesScrollArea::ModulePreferencesScrollArea(module_t *module, QWidg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (QComboBox *combo, findChildren<QComboBox *>()) {
|
||||||
|
pref_t *pref = VariantPointer<pref_t>::asPtr(combo->property(pref_prop_));
|
||||||
|
if (!pref) continue;
|
||||||
|
|
||||||
|
if (prefs_get_type(pref) == PREF_PROTO_TCP_SNDAMB_ENUM && !prefs_get_enum_radiobuttons(pref)) {
|
||||||
|
connect(combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, &ModulePreferencesScrollArea::enumComboBoxCurrentIndexChanged_PROTO_TCP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (QPushButton *pb, findChildren<QPushButton *>()) {
|
foreach (QPushButton *pb, findChildren<QPushButton *>()) {
|
||||||
pref_t *pref = VariantPointer<pref_t>::asPtr(pb->property(pref_prop_));
|
pref_t *pref = VariantPointer<pref_t>::asPtr(pb->property(pref_prop_));
|
||||||
if (!pref) continue;
|
if (!pref) continue;
|
||||||
|
@ -413,6 +469,12 @@ void ModulePreferencesScrollArea::updateWidgets()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prefs_get_type(pref) == PREF_PROTO_TCP_SNDAMB_ENUM && !prefs_get_enum_radiobuttons(pref)) {
|
||||||
|
MainWindow* topWidget = dynamic_cast<MainWindow*> (mainApp->mainWindow());
|
||||||
|
frame_data * fdata = topWidget->frameDataForRow((topWidget->selectedRows()).at(0));
|
||||||
|
enum_cb->setCurrentIndex(fdata->tcp_snd_manual_analysis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,3 +625,32 @@ void ModulePreferencesScrollArea::dirnamePushButtonClicked()
|
||||||
updateWidgets();
|
updateWidgets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dedicated event handling for TCP SEQ Analysis overriding.
|
||||||
|
*/
|
||||||
|
void ModulePreferencesScrollArea::enumComboBoxCurrentIndexChanged_PROTO_TCP(int index)
|
||||||
|
{
|
||||||
|
QComboBox *enum_cb = qobject_cast<QComboBox*>(sender());
|
||||||
|
if (!enum_cb) return;
|
||||||
|
|
||||||
|
pref_t *pref = VariantPointer<pref_t>::asPtr(enum_cb->property(pref_prop_));
|
||||||
|
if (!pref) return;
|
||||||
|
|
||||||
|
MainWindow* topWidget = dynamic_cast<MainWindow*> (mainApp->mainWindow());
|
||||||
|
|
||||||
|
// method 1 : apply to one single packet
|
||||||
|
/* frame_data * fdata = topWidget->frameDataForRow((topWidget->selectedRows()).at(0));
|
||||||
|
fdata->tcp_snd_manual_analysis = enum_cb->itemData(index).toInt();*/
|
||||||
|
|
||||||
|
// method 2 : we can leverage the functionality by allowing multiple selections
|
||||||
|
QList<int> rows = topWidget->selectedRows();
|
||||||
|
foreach (int row, rows) {
|
||||||
|
frame_data * fdata = topWidget->frameDataForRow(row);
|
||||||
|
fdata->tcp_snd_manual_analysis = enum_cb->itemData(index).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
prefs_set_enum_value(pref, enum_cb->itemData(index).toInt(), pref_current);
|
||||||
|
//prefs_set_enum_value(pref, enum_cb->itemData(index).toInt(), pref_stashed);
|
||||||
|
updateWidgets();
|
||||||
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ private slots:
|
||||||
void saveFilenamePushButtonClicked();
|
void saveFilenamePushButtonClicked();
|
||||||
void openFilenamePushButtonClicked();
|
void openFilenamePushButtonClicked();
|
||||||
void dirnamePushButtonClicked();
|
void dirnamePushButtonClicked();
|
||||||
|
void enumComboBoxCurrentIndexChanged_PROTO_TCP(int index);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MODULE_PREFERENCES_SCROLL_AREA_H
|
#endif // MODULE_PREFERENCES_SCROLL_AREA_H
|
||||||
|
|
|
@ -26,8 +26,10 @@
|
||||||
#include <ui/qt/utils/qt_ui_utils.h>
|
#include <ui/qt/utils/qt_ui_utils.h>
|
||||||
#include "uat_dialog.h"
|
#include "uat_dialog.h"
|
||||||
#include "main_application.h"
|
#include "main_application.h"
|
||||||
|
#include "main_window.h"
|
||||||
|
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
// To do:
|
// To do:
|
||||||
// - Elide really long items?
|
// - Elide really long items?
|
||||||
|
@ -79,6 +81,32 @@ private:
|
||||||
int enumval_;
|
int enumval_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EnumCustomTCPOverridePreferenceAction : public QAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EnumCustomTCPOverridePreferenceAction(pref_t *pref, const char *title, int enumval, QActionGroup *ag, QObject *parent=0) :
|
||||||
|
QAction(parent),
|
||||||
|
pref_(pref),
|
||||||
|
enumval_(enumval)
|
||||||
|
{
|
||||||
|
setText(title);
|
||||||
|
setActionGroup(ag);
|
||||||
|
setCheckable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int setEnumValue() {
|
||||||
|
return prefs_set_enum_value(pref_, enumval_, pref_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getEnumValue() { return enumval_; }
|
||||||
|
|
||||||
|
pref_t *getPref() { return pref_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
pref_t *pref_;
|
||||||
|
int enumval_;
|
||||||
|
};
|
||||||
|
|
||||||
class UatPreferenceAction : public QAction
|
class UatPreferenceAction : public QAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -90,7 +118,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void showUatDialog() {
|
void showUatDialog() {
|
||||||
UatDialog *uat_dlg = new UatDialog(qobject_cast<QWidget *>(parent()), prefs_get_uat_value(pref_));
|
UatDialog *uat_dlg = new UatDialog(parentWidget(), prefs_get_uat_value(pref_));
|
||||||
connect(uat_dlg, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals()));
|
connect(uat_dlg, SIGNAL(destroyed(QObject*)), mainApp, SLOT(flushAppSignals()));
|
||||||
uat_dlg->setWindowModality(Qt::ApplicationModal);
|
uat_dlg->setWindowModality(Qt::ApplicationModal);
|
||||||
uat_dlg->setAttribute(Qt::WA_DeleteOnClose);
|
uat_dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
@ -259,6 +287,47 @@ void ProtocolPreferencesMenu::addMenuItem(preference *pref)
|
||||||
case PREF_STATIC_TEXT:
|
case PREF_STATIC_TEXT:
|
||||||
case PREF_OBSOLETE:
|
case PREF_OBSOLETE:
|
||||||
break;
|
break;
|
||||||
|
case PREF_PROTO_TCP_SNDAMB_ENUM:
|
||||||
|
{
|
||||||
|
int override_id = -1;
|
||||||
|
|
||||||
|
MainWindow* topWidget = dynamic_cast<MainWindow*> (QApplication::topLevelAt(parentWidget()->mapToGlobal(QPoint())));
|
||||||
|
|
||||||
|
// the very first call does not have access to topWidget
|
||||||
|
if (topWidget) {
|
||||||
|
frame_data * fdata = topWidget->frameDataForRow((topWidget->selectedRows()).at(0));
|
||||||
|
if (fdata) {
|
||||||
|
// read stored value from frame
|
||||||
|
override_id = fdata->tcp_snd_manual_analysis;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* unexpected case */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *enum_menu = addMenu(prefs_get_title(pref));
|
||||||
|
const enum_val_t *enum_valp = prefs_get_enumvals(pref);
|
||||||
|
if (enum_valp && enum_valp->name) {
|
||||||
|
QActionGroup *ag = new QActionGroup(this);
|
||||||
|
while (enum_valp->name) {
|
||||||
|
EnumCustomTCPOverridePreferenceAction *epa = new EnumCustomTCPOverridePreferenceAction(pref, enum_valp->description, enum_valp->value, ag, this);
|
||||||
|
if (override_id>=0) {
|
||||||
|
if(override_id==enum_valp->value)
|
||||||
|
epa->setChecked(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(enum_valp->value == 0)
|
||||||
|
epa->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_menu->addAction(epa);
|
||||||
|
//connect(epa, SIGNAL(triggered(bool)), this, SLOT(enumPreferenceTriggered()));
|
||||||
|
connect(epa, SIGNAL(triggered(bool)), this, SLOT(enumCustomTCPOverridePreferenceTriggered()));
|
||||||
|
enum_valp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// A type we currently don't handle. Just open the prefs dialog.
|
// A type we currently don't handle. Just open the prefs dialog.
|
||||||
QString title = QString("%1" UTF8_HORIZONTAL_ELLIPSIS).arg(prefs_get_title(pref));
|
QString title = QString("%1" UTF8_HORIZONTAL_ELLIPSIS).arg(prefs_get_title(pref));
|
||||||
|
@ -331,6 +400,25 @@ void ProtocolPreferencesMenu::enumPreferenceTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolPreferencesMenu::enumCustomTCPOverridePreferenceTriggered()
|
||||||
|
{
|
||||||
|
EnumCustomTCPOverridePreferenceAction *epa = static_cast<EnumCustomTCPOverridePreferenceAction *>(QObject::sender());
|
||||||
|
if (!epa) return;
|
||||||
|
|
||||||
|
MainWindow* topWidget = dynamic_cast<MainWindow*> (QApplication::topLevelAt(parentWidget()->mapToGlobal(QPoint())));
|
||||||
|
frame_data * fdata = topWidget->frameDataForRow((topWidget->selectedRows()).at(0));
|
||||||
|
if (! fdata)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fdata->tcp_snd_manual_analysis != epa->getEnumValue()) { // Changed
|
||||||
|
fdata->tcp_snd_manual_analysis = epa->getEnumValue();
|
||||||
|
/* Protocol preference changes almost always affect dissection,
|
||||||
|
so don't bother checking flags */
|
||||||
|
mainApp->emitAppSignal(MainApplication::FieldsChanged);
|
||||||
|
mainApp->emitAppSignal(MainApplication::PacketDissectionChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolPreferencesMenu::uatPreferenceTriggered()
|
void ProtocolPreferencesMenu::uatPreferenceTriggered()
|
||||||
{
|
{
|
||||||
UatPreferenceAction *upa = static_cast<UatPreferenceAction *>(QObject::sender());
|
UatPreferenceAction *upa = static_cast<UatPreferenceAction *>(QObject::sender());
|
||||||
|
|
|
@ -43,6 +43,7 @@ private slots:
|
||||||
void boolPreferenceTriggered();
|
void boolPreferenceTriggered();
|
||||||
void enumPreferenceTriggered();
|
void enumPreferenceTriggered();
|
||||||
void uatPreferenceTriggered();
|
void uatPreferenceTriggered();
|
||||||
|
void enumCustomTCPOverridePreferenceTriggered();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __PROTOCOL_PREFERENCES_MENU_H__
|
#endif // __PROTOCOL_PREFERENCES_MENU_H__
|
||||||
|
|
|
@ -2997,14 +2997,6 @@ void WiresharkMainWindow::setMwFileName(QString fileName)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_data * WiresharkMainWindow::frameDataForRow(int row) const
|
|
||||||
{
|
|
||||||
if (packet_list_)
|
|
||||||
return packet_list_->getFDataForRow(row);
|
|
||||||
|
|
||||||
return Q_NULLPTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finds rtp id for selected stream and adds it to stream_ids
|
// Finds rtp id for selected stream and adds it to stream_ids
|
||||||
// If reverse is set, tries to find reverse stream too
|
// If reverse is set, tries to find reverse stream too
|
||||||
// Return error string if error happens
|
// Return error string if error happens
|
||||||
|
|
|
@ -130,8 +130,6 @@ public:
|
||||||
QString getMwFileName();
|
QString getMwFileName();
|
||||||
void setMwFileName(QString fileName);
|
void setMwFileName(QString fileName);
|
||||||
|
|
||||||
frame_data * frameDataForRow(int row) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||||
virtual bool event(QEvent *event);
|
virtual bool event(QEvent *event);
|
||||||
|
|
Loading…
Reference in New Issue