forked from osmocom/wireshark
Qt: Add a packet diagram view.
Add a new top-level view that shows each packet as a series of diagrams similar to what you'd find in a networking textook or an RFC. Add proto_item_set_bits_offset_len so that we can display some diagram fields correctly. Bugs / to do: - Make this a separate dialog instead of a main window view? - Handle bitfields / flags Change-Id: Iba4897a5bf1dcd73929dde6210d5483cf07f54df Reviewed-on: https://code.wireshark.org/review/37497 Reviewed-by: Gerald Combs <gerald@wireshark.org> Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
e846d238d7
commit
9b07412277
|
@ -42,6 +42,7 @@ since version 3.2.0:
|
||||||
* Wireshark is able to decode, play and save iLBC payload on platforms where iLBC library (https://github.com/TimothyGu/libilbc) is available.
|
* Wireshark is able to decode, play and save iLBC payload on platforms where iLBC library (https://github.com/TimothyGu/libilbc) is available.
|
||||||
* Decode As entries can now be copied from other profiles using a button in the dialog.
|
* Decode As entries can now be copied from other profiles using a button in the dialog.
|
||||||
* sshdump can now be copied in multiple instances. Each instance will show up a different interface and will have its own profile.
|
* sshdump can now be copied in multiple instances. Each instance will show up a different interface and will have its own profile.
|
||||||
|
* The main window now supports a packet diagram view, which shows each packet as a textbook-style diagram.
|
||||||
|
|
||||||
// === Removed Features and Support
|
// === Removed Features and Support
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ other GUI programs.
|
||||||
. The _packet bytes pane_ (see <<ChUsePacketBytesPaneSection>>) displays the
|
. The _packet bytes pane_ (see <<ChUsePacketBytesPaneSection>>) displays the
|
||||||
data from the packet selected in the packet list pane, and highlights the field
|
data from the packet selected in the packet list pane, and highlights the field
|
||||||
selected in the packet details pane.
|
selected in the packet details pane.
|
||||||
|
// . The _packet diagram pane_ (see <<ChUsePacketDiagramPaneSection>>) displays the packet selected in the packet list as a textbook-style diagram.
|
||||||
. The _statusbar_ (see <<ChUseStatusbarSection>>) shows some detailed
|
. The _statusbar_ (see <<ChUseStatusbarSection>>) shows some detailed
|
||||||
information about the current program state and the captured data.
|
information about the current program state and the captured data.
|
||||||
|
|
||||||
|
@ -406,6 +407,7 @@ image::wsug_graphics/ws-view-menu.png[{screenshot-attrs}]
|
||||||
|menu:Packet List[] ||This menu item hides or shows the packet list pane, see <<ChUsePacketListPaneSection>>.
|
|menu:Packet List[] ||This menu item hides or shows the packet list pane, see <<ChUsePacketListPaneSection>>.
|
||||||
|menu:Packet Details[] ||This menu item hides or shows the packet details pane, see <<ChUsePacketDetailsPaneSection>>.
|
|menu:Packet Details[] ||This menu item hides or shows the packet details pane, see <<ChUsePacketDetailsPaneSection>>.
|
||||||
|menu:Packet Bytes[] ||This menu item hides or shows the packet bytes pane, see <<ChUsePacketBytesPaneSection>>.
|
|menu:Packet Bytes[] ||This menu item hides or shows the packet bytes pane, see <<ChUsePacketBytesPaneSection>>.
|
||||||
|
// |menu:Packet Diagram[] ||This menu item hides or shows the packet diagram pane. See <<ChUsePacketDiagramPaneSection>>.
|
||||||
|menu:Time Display Format[Date and Time of Day: 1970-01-01 01:02:03.123456]|| Selecting this tells Wireshark to display the time stamps in date and time of day format, see <<ChWorkTimeFormatsSection>>.
|
|menu:Time Display Format[Date and Time of Day: 1970-01-01 01:02:03.123456]|| Selecting this tells Wireshark to display the time stamps in date and time of day format, see <<ChWorkTimeFormatsSection>>.
|
||||||
|
|
||||||
The fields “Time of Day”, “Date and Time of Day”, “Seconds Since Beginning of
|
The fields “Time of Day”, “Date and Time of Day”, “Seconds Since Beginning of
|
||||||
|
@ -1042,6 +1044,25 @@ The context menu (right mouse click) of the tab labels will show a list of all
|
||||||
available pages. This can be helpful if the size in the pane is too small for
|
available pages. This can be helpful if the size in the pane is too small for
|
||||||
all the tab labels.
|
all the tab labels.
|
||||||
|
|
||||||
|
[[ChUsePacketDiagramPaneSection]]
|
||||||
|
|
||||||
|
////
|
||||||
|
=== The “Packet Diagram” Pane
|
||||||
|
|
||||||
|
The packet diagram pane shows the current packet (selected in the “Packet List”
|
||||||
|
pane) as a diagram, similar to ones used in textbooks and IETF RFCs.
|
||||||
|
|
||||||
|
[[ChUseWiresharkDiagramPane]]
|
||||||
|
|
||||||
|
.The “Packet Diagram” pane
|
||||||
|
image::wsug_graphics/ws-diagram-pane.png[{screenshot-attrs}]
|
||||||
|
|
||||||
|
This pane shows the protocols and top-level protocol fields of the packet selected in the “Packet List” pane as a series of diagrams.
|
||||||
|
|
||||||
|
There is a context menu (right mouse click) available.
|
||||||
|
For details see <<ChWorkPacketDiagramPanePopUpMenu>>.
|
||||||
|
////
|
||||||
|
|
||||||
[[ChUseStatusbarSection]]
|
[[ChUseStatusbarSection]]
|
||||||
|
|
||||||
=== The Statusbar
|
=== The Statusbar
|
||||||
|
|
|
@ -1860,7 +1860,7 @@ dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
||||||
ti = proto_tree_add_item(tree, proto_ip, tvb, offset, hlen, ENC_NA);
|
ti = proto_tree_add_item(tree, proto_ip, tvb, offset, hlen, ENC_NA);
|
||||||
ip_tree = proto_item_add_subtree(ti, ett_ip);
|
ip_tree = proto_item_add_subtree(ti, ett_ip);
|
||||||
|
|
||||||
tf = proto_tree_add_item(ip_tree, hf_ip_version, tvb, offset, 1, ENC_NA);
|
tf = proto_tree_add_bits_item(ip_tree, hf_ip_version, tvb, 0, 4, ENC_NA);
|
||||||
if (iph->ip_ver != 4) {
|
if (iph->ip_ver != 4) {
|
||||||
col_add_fstr(pinfo->cinfo, COL_INFO,
|
col_add_fstr(pinfo->cinfo, COL_INFO,
|
||||||
"Bogus IPv4 version (%u, must be 4)", iph->ip_ver);
|
"Bogus IPv4 version (%u, must be 4)", iph->ip_ver);
|
||||||
|
@ -1997,7 +1997,6 @@ dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
||||||
|
|
||||||
if (ip_security_flag) {
|
if (ip_security_flag) {
|
||||||
/* RFC 3514 - The Security Flag in the IPv4 Header (April Fool's joke) */
|
/* RFC 3514 - The Security Flag in the IPv4 Header (April Fool's joke) */
|
||||||
proto_item *sf;
|
|
||||||
static int * const ip_flags_evil[] = {
|
static int * const ip_flags_evil[] = {
|
||||||
&hf_ip_flags_sf,
|
&hf_ip_flags_sf,
|
||||||
&hf_ip_flags_df,
|
&hf_ip_flags_df,
|
||||||
|
@ -2005,10 +2004,10 @@ dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
sf = proto_tree_add_bitmask_with_flags(ip_tree, tvb, offset + 6, hf_ip_flags,
|
tf = proto_tree_add_bitmask_with_flags(ip_tree, tvb, offset + 6, hf_ip_flags,
|
||||||
ett_ip_flags, ip_flags_evil, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_TFS | BMT_NO_INT);
|
ett_ip_flags, ip_flags_evil, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_TFS | BMT_NO_INT);
|
||||||
if (iph->ip_off & IP_RF) {
|
if (iph->ip_off & IP_RF) {
|
||||||
expert_add_info(pinfo, sf, &ei_ip_evil_packet);
|
expert_add_info(pinfo, tf, &ei_ip_evil_packet);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
static int * const ip_flags[] = {
|
static int * const ip_flags[] = {
|
||||||
|
@ -2017,12 +2016,13 @@ dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
||||||
&hf_ip_flags_mf,
|
&hf_ip_flags_mf,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
proto_tree_add_bitmask_with_flags(ip_tree, tvb, offset + 6, hf_ip_flags,
|
tf = proto_tree_add_bitmask_with_flags(ip_tree, tvb, offset + 6, hf_ip_flags,
|
||||||
ett_ip_flags, ip_flags, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_TFS | BMT_NO_INT);
|
ett_ip_flags, ip_flags, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_TFS | BMT_NO_INT);
|
||||||
}
|
}
|
||||||
|
proto_item_set_bits_offset_len(tf, 0, 3);
|
||||||
|
|
||||||
proto_tree_add_uint(ip_tree, hf_ip_frag_offset, tvb, offset + 6, 2, (iph->ip_off & IP_OFFSET)*8);
|
tf = proto_tree_add_uint(ip_tree, hf_ip_frag_offset, tvb, offset + 6, 2, (iph->ip_off & IP_OFFSET)*8);
|
||||||
|
proto_item_set_bits_offset_len(tf, 3, 13);
|
||||||
|
|
||||||
iph->ip_ttl = tvb_get_guint8(tvb, offset + 8);
|
iph->ip_ttl = tvb_get_guint8(tvb, offset + 8);
|
||||||
if (tree) {
|
if (tree) {
|
||||||
|
@ -2334,7 +2334,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
||||||
col_clear(pinfo->cinfo, COL_INFO);
|
col_clear(pinfo->cinfo, COL_INFO);
|
||||||
col_add_fstr(pinfo->cinfo, COL_INFO, "Bogus IP version (%u)", version);
|
col_add_fstr(pinfo->cinfo, COL_INFO, "Bogus IP version (%u)", version);
|
||||||
ip_tree = proto_item_add_subtree(ti, ett_ip);
|
ip_tree = proto_item_add_subtree(ti, ett_ip);
|
||||||
tf = proto_tree_add_item(ip_tree, hf_ip_version, tvb, 0, 1, ENC_NA);
|
tf = proto_tree_add_bits_item(ip_tree, hf_ip_version, tvb, 0, 4, ENC_NA);
|
||||||
expert_add_info(pinfo, tf, &ei_ip_bogus_ip_version);
|
expert_add_info(pinfo, tf, &ei_ip_bogus_ip_version);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2438,7 +2438,7 @@ proto_register_ip(void)
|
||||||
static hf_register_info hf[] = {
|
static hf_register_info hf[] = {
|
||||||
{ &hf_ip_version,
|
{ &hf_ip_version,
|
||||||
{ "Version", "ip.version", FT_UINT8, BASE_DEC,
|
{ "Version", "ip.version", FT_UINT8, BASE_DEC,
|
||||||
NULL, 0xF0, NULL, HFILL }},
|
NULL, 0x00, NULL, HFILL }},
|
||||||
|
|
||||||
{ &hf_ip_hdr_len,
|
{ &hf_ip_hdr_len,
|
||||||
{ "Header Length", "ip.hdr_len", FT_UINT8, BASE_DEC,
|
{ "Header Length", "ip.hdr_len", FT_UINT8, BASE_DEC,
|
||||||
|
|
|
@ -6439,6 +6439,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
||||||
"%u bytes (%u)", tcph->th_hlen, tcph->th_hlen>>2);
|
"%u bytes (%u)", tcph->th_hlen, tcph->th_hlen>>2);
|
||||||
tf = proto_tree_add_uint_format(tcp_tree, hf_tcp_flags, tvb, offset + 12, 2,
|
tf = proto_tree_add_uint_format(tcp_tree, hf_tcp_flags, tvb, offset + 12, 2,
|
||||||
tcph->th_flags, "Flags: 0x%03x (%s)", tcph->th_flags, flags_str);
|
tcph->th_flags, "Flags: 0x%03x (%s)", tcph->th_flags, flags_str);
|
||||||
|
proto_item_set_bits_offset_len(tf, 4, 12);
|
||||||
field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
|
field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
|
||||||
proto_tree_add_boolean(field_tree, hf_tcp_flags_res, tvb, offset + 12, 1, tcph->th_flags);
|
proto_tree_add_boolean(field_tree, hf_tcp_flags_res, tvb, offset + 12, 1, tcph->th_flags);
|
||||||
proto_tree_add_boolean(field_tree, hf_tcp_flags_ns, tvb, offset + 12, 1, tcph->th_flags);
|
proto_tree_add_boolean(field_tree, hf_tcp_flags_ns, tvb, offset + 12, 1, tcph->th_flags);
|
||||||
|
|
|
@ -122,6 +122,7 @@ static const enum_val_t gui_layout_content[] = {
|
||||||
{"PLIST", "PLIST", 1},
|
{"PLIST", "PLIST", 1},
|
||||||
{"PDETAILS", "PDETAILS", 2},
|
{"PDETAILS", "PDETAILS", 2},
|
||||||
{"PBYTES", "PBYTES", 3},
|
{"PBYTES", "PBYTES", 3},
|
||||||
|
{"PDIAGRAM", "PDIAGRAM", 4},
|
||||||
{NULL, NULL, -1}
|
{NULL, NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,8 @@ typedef enum {
|
||||||
layout_pane_content_none,
|
layout_pane_content_none,
|
||||||
layout_pane_content_plist,
|
layout_pane_content_plist,
|
||||||
layout_pane_content_pdetails,
|
layout_pane_content_pdetails,
|
||||||
layout_pane_content_pbytes
|
layout_pane_content_pbytes,
|
||||||
|
layout_pane_content_pdiagram,
|
||||||
} layout_pane_content_e;
|
} layout_pane_content_e;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -6827,6 +6827,15 @@ proto_item_get_len(const proto_item *pi)
|
||||||
return fi ? fi->length : -1;
|
return fi ? fi->length : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
proto_item_set_bits_offset_len(proto_item *ti, int bits_offset, int bits_len) {
|
||||||
|
if (!ti) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FI_SET_FLAG(PNODE_FINFO(ti), FI_BITS_OFFSET(bits_offset));
|
||||||
|
FI_SET_FLAG(PNODE_FINFO(ti), FI_BITS_SIZE(bits_len));
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
proto_item_get_display_repr(wmem_allocator_t *scope, proto_item *pi)
|
proto_item_get_display_repr(wmem_allocator_t *scope, proto_item *pi)
|
||||||
{
|
{
|
||||||
|
|
|
@ -991,7 +991,7 @@ static inline gboolean proto_item_is_url(proto_item *ti) {
|
||||||
#define PROTO_ITEM_IS_URL(ti) proto_item_is_url((ti))
|
#define PROTO_ITEM_IS_URL(ti) proto_item_is_url((ti))
|
||||||
|
|
||||||
/** Mark this protocol field as a URL
|
/** Mark this protocol field as a URL
|
||||||
* @param ti The item to mark as a URL. May be NULL.
|
* @param ti The item to mark as a URL. May be NULL.
|
||||||
*/
|
*/
|
||||||
static inline void proto_item_set_url(proto_item *ti) {
|
static inline void proto_item_set_url(proto_item *ti) {
|
||||||
if (ti) {
|
if (ti) {
|
||||||
|
@ -1107,6 +1107,13 @@ WS_DLL_PUBLIC void proto_item_set_end(proto_item *pi, tvbuff_t *tvb, gint end);
|
||||||
@return the current length */
|
@return the current length */
|
||||||
WS_DLL_PUBLIC int proto_item_get_len(const proto_item *pi);
|
WS_DLL_PUBLIC int proto_item_get_len(const proto_item *pi);
|
||||||
|
|
||||||
|
/** Set the bit offset and length for the specified proto_item.
|
||||||
|
* @param ti The item to set.
|
||||||
|
* @param bits_offset The number of bits from the beginning of the field.
|
||||||
|
* @param bits_offset The new length in bits.
|
||||||
|
*/
|
||||||
|
void proto_item_set_bits_offset_len(proto_item *ti, int bits_offset, int bits_len);
|
||||||
|
|
||||||
/** Get display representation of a proto_item.
|
/** Get display representation of a proto_item.
|
||||||
* Can be used, for example, to append that to the parent item of
|
* Can be used, for example, to append that to the parent item of
|
||||||
* that item.
|
* that item.
|
||||||
|
|
|
@ -17,3 +17,4 @@ mkdir ~/.config/wireshark/profiles/ctest
|
||||||
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T ek -r test/captures/dhcp.pcap > test/baseline/dhcp.ek
|
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T ek -r test/captures/dhcp.pcap > test/baseline/dhcp.ek
|
||||||
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T json -r test/captures/dhcp.pcap > test/baseline/dhcp.json
|
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T json -r test/captures/dhcp.pcap > test/baseline/dhcp.json
|
||||||
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T jsonraw -r test/captures/dhcp.pcap > test/baseline/dhcp.jsonraw
|
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T jsonraw -r test/captures/dhcp.pcap > test/baseline/dhcp.jsonraw
|
||||||
|
TZ=UTC WIRESHARK_RUN_FROM_BUILD_DIRECTORY=1 build/run/tshark -C ctest -T ek -r test/captures/dhcp.pcap -x > test/baseline/dhcp-raw.ek
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -288,10 +288,10 @@
|
||||||
],
|
],
|
||||||
"ip": {
|
"ip": {
|
||||||
"ip.version_raw": [
|
"ip.version_raw": [
|
||||||
"4",
|
"45",
|
||||||
14,
|
14,
|
||||||
1,
|
1,
|
||||||
240,
|
0,
|
||||||
4
|
4
|
||||||
],
|
],
|
||||||
"ip.hdr_len_raw": [
|
"ip.hdr_len_raw": [
|
||||||
|
@ -1162,10 +1162,10 @@
|
||||||
],
|
],
|
||||||
"ip": {
|
"ip": {
|
||||||
"ip.version_raw": [
|
"ip.version_raw": [
|
||||||
"4",
|
"45",
|
||||||
14,
|
14,
|
||||||
1,
|
1,
|
||||||
240,
|
0,
|
||||||
4
|
4
|
||||||
],
|
],
|
||||||
"ip.hdr_len_raw": [
|
"ip.hdr_len_raw": [
|
||||||
|
@ -2054,10 +2054,10 @@
|
||||||
],
|
],
|
||||||
"ip": {
|
"ip": {
|
||||||
"ip.version_raw": [
|
"ip.version_raw": [
|
||||||
"4",
|
"45",
|
||||||
14,
|
14,
|
||||||
1,
|
1,
|
||||||
240,
|
0,
|
||||||
4
|
4
|
||||||
],
|
],
|
||||||
"ip.hdr_len_raw": [
|
"ip.hdr_len_raw": [
|
||||||
|
@ -2958,10 +2958,10 @@
|
||||||
],
|
],
|
||||||
"ip": {
|
"ip": {
|
||||||
"ip.version_raw": [
|
"ip.version_raw": [
|
||||||
"4",
|
"45",
|
||||||
14,
|
14,
|
||||||
1,
|
1,
|
||||||
240,
|
0,
|
||||||
4
|
4
|
||||||
],
|
],
|
||||||
"ip.hdr_len_raw": [
|
"ip.hdr_len_raw": [
|
||||||
|
|
|
@ -181,6 +181,7 @@ set(WIRESHARK_QT_HEADERS
|
||||||
mtp3_summary_dialog.h
|
mtp3_summary_dialog.h
|
||||||
multicast_statistics_dialog.h
|
multicast_statistics_dialog.h
|
||||||
packet_comment_dialog.h
|
packet_comment_dialog.h
|
||||||
|
packet_diagram.h
|
||||||
packet_dialog.h
|
packet_dialog.h
|
||||||
packet_format_group_box.h
|
packet_format_group_box.h
|
||||||
packet_list.h
|
packet_list.h
|
||||||
|
@ -406,6 +407,7 @@ set(WIRESHARK_QT_SRC
|
||||||
manage_interfaces_dialog.cpp
|
manage_interfaces_dialog.cpp
|
||||||
module_preferences_scroll_area.cpp
|
module_preferences_scroll_area.cpp
|
||||||
packet_comment_dialog.cpp
|
packet_comment_dialog.cpp
|
||||||
|
packet_diagram.cpp
|
||||||
packet_dialog.cpp
|
packet_dialog.cpp
|
||||||
packet_format_group_box.cpp
|
packet_format_group_box.cpp
|
||||||
packet_list.cpp
|
packet_list.cpp
|
||||||
|
|
|
@ -1462,7 +1462,7 @@ void IOGraphDialog::on_buttonBox_helpRequested()
|
||||||
wsApp->helpTopicAction(HELP_STATS_IO_GRAPH_DIALOG);
|
wsApp->helpTopicAction(HELP_STATS_IO_GRAPH_DIALOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX - Copied from tcp_stream_dialog. This should be common code.
|
// XXX - We have similar code in tcp_stream_dialog and packet_diagram. Should this be a common routine?
|
||||||
void IOGraphDialog::on_buttonBox_accepted()
|
void IOGraphDialog::on_buttonBox_accepted()
|
||||||
{
|
{
|
||||||
QString file_name, extension;
|
QString file_name, extension;
|
||||||
|
|
|
@ -106,6 +106,9 @@ void LayoutPreferencesFrame::updateWidgets()
|
||||||
case layout_pane_content_pbytes:
|
case layout_pane_content_pbytes:
|
||||||
ui->pane1PacketBytesRadioButton->setChecked(true);
|
ui->pane1PacketBytesRadioButton->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
case layout_pane_content_pdiagram:
|
||||||
|
ui->pane1PacketDiagramRadioButton->setChecked(true);
|
||||||
|
break;
|
||||||
case layout_pane_content_none:
|
case layout_pane_content_none:
|
||||||
ui->pane1NoneRadioButton->setChecked(true);
|
ui->pane1NoneRadioButton->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
@ -121,6 +124,9 @@ void LayoutPreferencesFrame::updateWidgets()
|
||||||
case layout_pane_content_pbytes:
|
case layout_pane_content_pbytes:
|
||||||
ui->pane2PacketBytesRadioButton->setChecked(true);
|
ui->pane2PacketBytesRadioButton->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
case layout_pane_content_pdiagram:
|
||||||
|
ui->pane2PacketDiagramRadioButton->setChecked(true);
|
||||||
|
break;
|
||||||
case layout_pane_content_none:
|
case layout_pane_content_none:
|
||||||
ui->pane2NoneRadioButton->setChecked(true);
|
ui->pane2NoneRadioButton->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
@ -136,6 +142,9 @@ void LayoutPreferencesFrame::updateWidgets()
|
||||||
case layout_pane_content_pbytes:
|
case layout_pane_content_pbytes:
|
||||||
ui->pane3PacketBytesRadioButton->setChecked(true);
|
ui->pane3PacketBytesRadioButton->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
case layout_pane_content_pdiagram:
|
||||||
|
ui->pane3PacketDiagramRadioButton->setChecked(true);
|
||||||
|
break;
|
||||||
case layout_pane_content_none:
|
case layout_pane_content_none:
|
||||||
ui->pane3NoneRadioButton->setChecked(true);
|
ui->pane3NoneRadioButton->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
@ -208,6 +217,16 @@ void LayoutPreferencesFrame::on_pane1PacketBytesRadioButton_toggled(bool checked
|
||||||
ui->pane3NoneRadioButton->click();
|
ui->pane3NoneRadioButton->click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayoutPreferencesFrame::on_pane1PacketDiagramRadioButton_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (!checked) return;
|
||||||
|
prefs_set_enum_value(pref_layout_content_1_, layout_pane_content_pdiagram, pref_stashed);
|
||||||
|
if (ui->pane2PacketDiagramRadioButton->isChecked())
|
||||||
|
ui->pane2NoneRadioButton->click();
|
||||||
|
if (ui->pane3PacketDiagramRadioButton->isChecked())
|
||||||
|
ui->pane3NoneRadioButton->click();
|
||||||
|
}
|
||||||
|
|
||||||
void LayoutPreferencesFrame::on_pane1NoneRadioButton_toggled(bool checked)
|
void LayoutPreferencesFrame::on_pane1NoneRadioButton_toggled(bool checked)
|
||||||
{
|
{
|
||||||
if (!checked) return;
|
if (!checked) return;
|
||||||
|
@ -244,6 +263,16 @@ void LayoutPreferencesFrame::on_pane2PacketBytesRadioButton_toggled(bool checked
|
||||||
ui->pane3NoneRadioButton->click();
|
ui->pane3NoneRadioButton->click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayoutPreferencesFrame::on_pane2PacketDiagramRadioButton_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (!checked) return;
|
||||||
|
prefs_set_enum_value(pref_layout_content_2_, layout_pane_content_pdiagram, pref_stashed);
|
||||||
|
if (ui->pane1PacketDiagramRadioButton->isChecked())
|
||||||
|
ui->pane1NoneRadioButton->click();
|
||||||
|
if (ui->pane3PacketDiagramRadioButton->isChecked())
|
||||||
|
ui->pane3NoneRadioButton->click();
|
||||||
|
}
|
||||||
|
|
||||||
void LayoutPreferencesFrame::on_pane2NoneRadioButton_toggled(bool checked)
|
void LayoutPreferencesFrame::on_pane2NoneRadioButton_toggled(bool checked)
|
||||||
{
|
{
|
||||||
if (!checked) return;
|
if (!checked) return;
|
||||||
|
@ -280,6 +309,16 @@ void LayoutPreferencesFrame::on_pane3PacketBytesRadioButton_toggled(bool checked
|
||||||
ui->pane2NoneRadioButton->click();
|
ui->pane2NoneRadioButton->click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayoutPreferencesFrame::on_pane3PacketDiagramRadioButton_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (!checked) return;
|
||||||
|
prefs_set_enum_value(pref_layout_content_3_, layout_pane_content_pdiagram, pref_stashed);
|
||||||
|
if (ui->pane1PacketDiagramRadioButton->isChecked())
|
||||||
|
ui->pane1NoneRadioButton->click();
|
||||||
|
if (ui->pane2PacketDiagramRadioButton->isChecked())
|
||||||
|
ui->pane2NoneRadioButton->click();
|
||||||
|
}
|
||||||
|
|
||||||
void LayoutPreferencesFrame::on_pane3NoneRadioButton_toggled(bool checked)
|
void LayoutPreferencesFrame::on_pane3NoneRadioButton_toggled(bool checked)
|
||||||
{
|
{
|
||||||
if (!checked) return;
|
if (!checked) return;
|
||||||
|
|
|
@ -54,14 +54,17 @@ private slots:
|
||||||
void on_pane1PacketListRadioButton_toggled(bool checked);
|
void on_pane1PacketListRadioButton_toggled(bool checked);
|
||||||
void on_pane1PacketDetailsRadioButton_toggled(bool checked);
|
void on_pane1PacketDetailsRadioButton_toggled(bool checked);
|
||||||
void on_pane1PacketBytesRadioButton_toggled(bool checked);
|
void on_pane1PacketBytesRadioButton_toggled(bool checked);
|
||||||
|
void on_pane1PacketDiagramRadioButton_toggled(bool checked);
|
||||||
void on_pane1NoneRadioButton_toggled(bool checked);
|
void on_pane1NoneRadioButton_toggled(bool checked);
|
||||||
void on_pane2PacketListRadioButton_toggled(bool checked);
|
void on_pane2PacketListRadioButton_toggled(bool checked);
|
||||||
void on_pane2PacketDetailsRadioButton_toggled(bool checked);
|
void on_pane2PacketDetailsRadioButton_toggled(bool checked);
|
||||||
void on_pane2PacketBytesRadioButton_toggled(bool checked);
|
void on_pane2PacketBytesRadioButton_toggled(bool checked);
|
||||||
|
void on_pane2PacketDiagramRadioButton_toggled(bool checked);
|
||||||
void on_pane2NoneRadioButton_toggled(bool checked);
|
void on_pane2NoneRadioButton_toggled(bool checked);
|
||||||
void on_pane3PacketListRadioButton_toggled(bool checked);
|
void on_pane3PacketListRadioButton_toggled(bool checked);
|
||||||
void on_pane3PacketDetailsRadioButton_toggled(bool checked);
|
void on_pane3PacketDetailsRadioButton_toggled(bool checked);
|
||||||
void on_pane3PacketBytesRadioButton_toggled(bool checked);
|
void on_pane3PacketBytesRadioButton_toggled(bool checked);
|
||||||
|
void on_pane3PacketDiagramRadioButton_toggled(bool checked);
|
||||||
void on_pane3NoneRadioButton_toggled(bool checked);
|
void on_pane3NoneRadioButton_toggled(bool checked);
|
||||||
void on_restoreButtonBox_clicked(QAbstractButton *button);
|
void on_restoreButtonBox_clicked(QAbstractButton *button);
|
||||||
void on_packetListSeparatorCheckBox_toggled(bool checked);
|
void on_packetListSeparatorCheckBox_toggled(bool checked);
|
||||||
|
|
|
@ -212,6 +212,16 @@
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="pane1PacketDiagramRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Packet Diagram</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">pane1ButtonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="pane1NoneRadioButton">
|
<widget class="QRadioButton" name="pane1NoneRadioButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -263,6 +273,16 @@
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="pane2PacketDiagramRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Packet Diagram</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">pane2ButtonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="pane2NoneRadioButton">
|
<widget class="QRadioButton" name="pane2NoneRadioButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -314,6 +334,16 @@
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="pane3PacketDiagramRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Packet Diagram</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">pane3ButtonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="pane3NoneRadioButton">
|
<widget class="QRadioButton" name="pane3NoneRadioButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -57,6 +57,7 @@ DIAG_ON(frame-larger-than=)
|
||||||
#include "funnel_statistics.h"
|
#include "funnel_statistics.h"
|
||||||
#include "import_text_dialog.h"
|
#include "import_text_dialog.h"
|
||||||
#include "interface_toolbar.h"
|
#include "interface_toolbar.h"
|
||||||
|
#include "packet_diagram.h"
|
||||||
#include "packet_list.h"
|
#include "packet_list.h"
|
||||||
#include "proto_tree.h"
|
#include "proto_tree.h"
|
||||||
#include "simple_dialog.h"
|
#include "simple_dialog.h"
|
||||||
|
@ -466,20 +467,23 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
packet_list_->setProtoTree(proto_tree_);
|
packet_list_->setProtoTree(proto_tree_);
|
||||||
packet_list_->installEventFilter(this);
|
packet_list_->installEventFilter(this);
|
||||||
|
|
||||||
|
packet_diagram_ = new PacketDiagram(&master_split_);
|
||||||
|
|
||||||
welcome_page_ = main_ui_->welcomePage;
|
welcome_page_ = main_ui_->welcomePage;
|
||||||
|
|
||||||
connect(proto_tree_, SIGNAL(fieldSelected(FieldInformation *)),
|
connect(proto_tree_, &ProtoTree::fieldSelected,
|
||||||
this, SIGNAL(fieldSelected(FieldInformation *)));
|
this, &MainWindow::fieldSelected);
|
||||||
connect(packet_list_, SIGNAL(fieldSelected(FieldInformation *)),
|
connect(packet_list_, &PacketList::fieldSelected,
|
||||||
this, SIGNAL(fieldSelected(FieldInformation *)));
|
this, &MainWindow::fieldSelected);
|
||||||
connect(this, SIGNAL(fieldSelected(FieldInformation *)),
|
connect(this, &MainWindow::fieldSelected,
|
||||||
this, SLOT(setMenusForSelectedTreeRow(FieldInformation *)));
|
this, &MainWindow::setMenusForSelectedTreeRow);
|
||||||
connect(this, SIGNAL(fieldSelected(FieldInformation *)),
|
connect(this, &MainWindow::fieldSelected,
|
||||||
main_ui_->statusBar, SLOT(selectedFieldChanged(FieldInformation *)));
|
main_ui_->statusBar, &MainStatusBar::selectedFieldChanged);
|
||||||
|
|
||||||
connect(this, SIGNAL(fieldHighlight(FieldInformation *)),
|
connect(this, &MainWindow::fieldHighlight,
|
||||||
main_ui_->statusBar, SLOT(highlightedFieldChanged(FieldInformation *)));
|
main_ui_->statusBar, &MainStatusBar::highlightedFieldChanged);
|
||||||
connect(wsApp, SIGNAL(captureActive(int)), this, SIGNAL(captureActive(int)));
|
connect(wsApp, &WiresharkApplication::captureActive,
|
||||||
|
this, &MainWindow::captureActive);
|
||||||
|
|
||||||
byte_view_tab_ = new ByteViewTab(&master_split_);
|
byte_view_tab_ = new ByteViewTab(&master_split_);
|
||||||
|
|
||||||
|
@ -543,14 +547,14 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
filter_expression_toolbar_, &FilterExpressionToolBar::filterExpressionsChanged);
|
filter_expression_toolbar_, &FilterExpressionToolBar::filterExpressionsChanged);
|
||||||
|
|
||||||
/* Connect change of capture file */
|
/* Connect change of capture file */
|
||||||
connect(this, SIGNAL(setCaptureFile(capture_file*)),
|
connect(this, &MainWindow::setCaptureFile,
|
||||||
main_ui_->searchFrame, SLOT(setCaptureFile(capture_file*)));
|
main_ui_->searchFrame, &SearchFrame::setCaptureFile);
|
||||||
connect(this, SIGNAL(setCaptureFile(capture_file*)),
|
connect(this, &MainWindow::setCaptureFile,
|
||||||
main_ui_->statusBar, SLOT(setCaptureFile(capture_file*)));
|
main_ui_->statusBar, &MainStatusBar::setCaptureFile);
|
||||||
connect(this, SIGNAL(setCaptureFile(capture_file*)),
|
connect(this, &MainWindow::setCaptureFile,
|
||||||
packet_list_, SLOT(setCaptureFile(capture_file*)));
|
packet_list_, &PacketList::setCaptureFile);
|
||||||
connect(this, SIGNAL(setCaptureFile(capture_file*)),
|
connect(this, &MainWindow::setCaptureFile,
|
||||||
proto_tree_, SLOT(setCaptureFile(capture_file*)));
|
proto_tree_, &ProtoTree::setCaptureFile);
|
||||||
|
|
||||||
connect(wsApp, SIGNAL(zoomMonospaceFont(QFont)),
|
connect(wsApp, SIGNAL(zoomMonospaceFont(QFont)),
|
||||||
packet_list_, SLOT(setMonospaceFont(QFont)));
|
packet_list_, SLOT(setMonospaceFont(QFont)));
|
||||||
|
@ -701,6 +705,7 @@ QMenu *MainWindow::createPopupMenu()
|
||||||
menu->addAction(main_ui_->actionViewPacketList);
|
menu->addAction(main_ui_->actionViewPacketList);
|
||||||
menu->addAction(main_ui_->actionViewPacketDetails);
|
menu->addAction(main_ui_->actionViewPacketDetails);
|
||||||
menu->addAction(main_ui_->actionViewPacketBytes);
|
menu->addAction(main_ui_->actionViewPacketBytes);
|
||||||
|
menu->addAction(main_ui_->actionViewPacketDiagram);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2058,6 +2063,7 @@ void MainWindow::initShowHideMainWidgets()
|
||||||
shmw_actions[main_ui_->actionViewPacketList] = packet_list_;
|
shmw_actions[main_ui_->actionViewPacketList] = packet_list_;
|
||||||
shmw_actions[main_ui_->actionViewPacketDetails] = proto_tree_;
|
shmw_actions[main_ui_->actionViewPacketDetails] = proto_tree_;
|
||||||
shmw_actions[main_ui_->actionViewPacketBytes] = byte_view_tab_;
|
shmw_actions[main_ui_->actionViewPacketBytes] = byte_view_tab_;
|
||||||
|
shmw_actions[main_ui_->actionViewPacketDiagram] = packet_diagram_;
|
||||||
|
|
||||||
foreach(QAction *shmwa, shmw_actions.keys()) {
|
foreach(QAction *shmwa, shmw_actions.keys()) {
|
||||||
shmwa->setData(QVariant::fromValue(shmw_actions[shmwa]));
|
shmwa->setData(QVariant::fromValue(shmw_actions[shmwa]));
|
||||||
|
|
|
@ -85,6 +85,7 @@ class FilterDialog;
|
||||||
class FunnelStatistics;
|
class FunnelStatistics;
|
||||||
class WelcomePage;
|
class WelcomePage;
|
||||||
class PacketCommentDialog;
|
class PacketCommentDialog;
|
||||||
|
class PacketDiagram;
|
||||||
class PacketList;
|
class PacketList;
|
||||||
class ProtoTree;
|
class ProtoTree;
|
||||||
#if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
|
#if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
|
||||||
|
@ -191,7 +192,8 @@ private:
|
||||||
// probably be full-on values instead of pointers.
|
// probably be full-on values instead of pointers.
|
||||||
PacketList *packet_list_;
|
PacketList *packet_list_;
|
||||||
ProtoTree *proto_tree_;
|
ProtoTree *proto_tree_;
|
||||||
ByteViewTab * byte_view_tab_;
|
ByteViewTab *byte_view_tab_;
|
||||||
|
PacketDiagram *packet_diagram_;
|
||||||
QWidget *previous_focus_;
|
QWidget *previous_focus_;
|
||||||
FileSetDialog *file_set_dialog_;
|
FileSetDialog *file_set_dialog_;
|
||||||
QWidget empty_pane_;
|
QWidget empty_pane_;
|
||||||
|
|
|
@ -362,6 +362,7 @@
|
||||||
<addaction name="actionViewPacketList"/>
|
<addaction name="actionViewPacketList"/>
|
||||||
<addaction name="actionViewPacketDetails"/>
|
<addaction name="actionViewPacketDetails"/>
|
||||||
<addaction name="actionViewPacketBytes"/>
|
<addaction name="actionViewPacketBytes"/>
|
||||||
|
<addaction name="actionViewPacketDiagram"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="menuTime_Display_Format"/>
|
<addaction name="menuTime_Display_Format"/>
|
||||||
<addaction name="menuName_Resolution"/>
|
<addaction name="menuName_Resolution"/>
|
||||||
|
@ -2473,6 +2474,20 @@
|
||||||
<string>Show or hide the packet bytes</string>
|
<string>Show or hide the packet bytes</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionViewPacketDiagram">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Packet &Diagram</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show or hide the packet diagram</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionViewInternalsConversationHashTables">
|
<action name="actionViewInternalsConversationHashTables">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Conversation Hash Tables</string>
|
<string>&Conversation Hash Tables</string>
|
||||||
|
|
|
@ -24,9 +24,10 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
|
|
||||||
#include <ui/qt/packet_list.h>
|
|
||||||
#include <ui/qt/proto_tree.h>
|
|
||||||
#include <ui/qt/byte_view_tab.h>
|
#include <ui/qt/byte_view_tab.h>
|
||||||
|
#include <ui/qt/packet_list.h>
|
||||||
|
#include <ui/qt/packet_diagram.h>
|
||||||
|
#include <ui/qt/proto_tree.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The generated Ui_MainWindow::setupUi() can grow larger than our configured limit,
|
* The generated Ui_MainWindow::setupUi() can grow larger than our configured limit,
|
||||||
|
@ -56,6 +57,8 @@ QWidget* MainWindow::getLayoutWidget(layout_pane_content_e type) {
|
||||||
return proto_tree_;
|
return proto_tree_;
|
||||||
case layout_pane_content_pbytes:
|
case layout_pane_content_pbytes:
|
||||||
return byte_view_tab_;
|
return byte_view_tab_;
|
||||||
|
case layout_pane_content_pdiagram:
|
||||||
|
return packet_diagram_;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -76,7 +79,8 @@ void MainWindow::layoutPanes()
|
||||||
<< prefs.gui_layout_content_3
|
<< prefs.gui_layout_content_3
|
||||||
<< recent.packet_list_show
|
<< recent.packet_list_show
|
||||||
<< recent.tree_view_show
|
<< recent.tree_view_show
|
||||||
<< recent.byte_view_show;
|
<< recent.byte_view_show
|
||||||
|
<< recent.packet_diagram_show;
|
||||||
|
|
||||||
if (cur_layout_ == new_layout) return;
|
if (cur_layout_ == new_layout) return;
|
||||||
|
|
||||||
|
@ -84,10 +88,11 @@ void MainWindow::layoutPanes()
|
||||||
|
|
||||||
// Reparent all widgets and add them back in the proper order below.
|
// Reparent all widgets and add them back in the proper order below.
|
||||||
// This hides each widget as well.
|
// This hides each widget as well.
|
||||||
packet_list_->freeze(); // Clears tree and byte view tabs.
|
packet_list_->freeze(); // Clears tree, byte view tabs, and diagram.
|
||||||
packet_list_->setParent(main_ui_->mainStack);
|
packet_list_->setParent(main_ui_->mainStack);
|
||||||
proto_tree_->setParent(main_ui_->mainStack);
|
proto_tree_->setParent(main_ui_->mainStack);
|
||||||
byte_view_tab_->setParent(main_ui_->mainStack);
|
byte_view_tab_->setParent(main_ui_->mainStack);
|
||||||
|
packet_diagram_->setParent(main_ui_->mainStack);
|
||||||
empty_pane_.setParent(main_ui_->mainStack);
|
empty_pane_.setParent(main_ui_->mainStack);
|
||||||
extra_split_.setParent(main_ui_->mainStack);
|
extra_split_.setParent(main_ui_->mainStack);
|
||||||
|
|
||||||
|
@ -156,6 +161,7 @@ void MainWindow::layoutPanes()
|
||||||
packet_list_->setVisible(ms_children.contains(packet_list_) && recent.packet_list_show);
|
packet_list_->setVisible(ms_children.contains(packet_list_) && recent.packet_list_show);
|
||||||
proto_tree_->setVisible(ms_children.contains(proto_tree_) && recent.tree_view_show);
|
proto_tree_->setVisible(ms_children.contains(proto_tree_) && recent.tree_view_show);
|
||||||
byte_view_tab_->setVisible(ms_children.contains(byte_view_tab_) && recent.byte_view_show);
|
byte_view_tab_->setVisible(ms_children.contains(byte_view_tab_) && recent.byte_view_show);
|
||||||
|
packet_diagram_->setVisible(ms_children.contains(packet_diagram_) && recent.packet_diagram_show);
|
||||||
|
|
||||||
// Show the packet list here to prevent pending resize events changing columns
|
// Show the packet list here to prevent pending resize events changing columns
|
||||||
// when the packet list is set as current widget for the first time.
|
// when the packet list is set as current widget for the first time.
|
||||||
|
|
|
@ -127,6 +127,7 @@ DIAG_ON(frame-larger-than=)
|
||||||
#include "mtp3_summary_dialog.h"
|
#include "mtp3_summary_dialog.h"
|
||||||
#include "multicast_statistics_dialog.h"
|
#include "multicast_statistics_dialog.h"
|
||||||
#include "packet_comment_dialog.h"
|
#include "packet_comment_dialog.h"
|
||||||
|
#include "packet_diagram.h"
|
||||||
#include "packet_dialog.h"
|
#include "packet_dialog.h"
|
||||||
#include "packet_list.h"
|
#include "packet_list.h"
|
||||||
#include "credentials_dialog.h"
|
#include "credentials_dialog.h"
|
||||||
|
@ -360,6 +361,7 @@ void MainWindow::updatePreferenceActions()
|
||||||
main_ui_->actionViewPacketList->setEnabled(prefs_has_layout_pane_content(layout_pane_content_plist));
|
main_ui_->actionViewPacketList->setEnabled(prefs_has_layout_pane_content(layout_pane_content_plist));
|
||||||
main_ui_->actionViewPacketDetails->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdetails));
|
main_ui_->actionViewPacketDetails->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdetails));
|
||||||
main_ui_->actionViewPacketBytes->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pbytes));
|
main_ui_->actionViewPacketBytes->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pbytes));
|
||||||
|
main_ui_->actionViewPacketDiagram->setEnabled(prefs_has_layout_pane_content(layout_pane_content_pdiagram));
|
||||||
|
|
||||||
main_ui_->actionViewNameResolutionPhysical->setChecked(gbl_resolv_flags.mac_name);
|
main_ui_->actionViewNameResolutionPhysical->setChecked(gbl_resolv_flags.mac_name);
|
||||||
main_ui_->actionViewNameResolutionNetwork->setChecked(gbl_resolv_flags.network_name);
|
main_ui_->actionViewNameResolutionNetwork->setChecked(gbl_resolv_flags.network_name);
|
||||||
|
@ -378,6 +380,7 @@ void MainWindow::updateRecentActions()
|
||||||
main_ui_->actionViewPacketList->setChecked(recent.packet_list_show && prefs_has_layout_pane_content(layout_pane_content_plist));
|
main_ui_->actionViewPacketList->setChecked(recent.packet_list_show && prefs_has_layout_pane_content(layout_pane_content_plist));
|
||||||
main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails));
|
main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails));
|
||||||
main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes));
|
main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes));
|
||||||
|
main_ui_->actionViewPacketDiagram->setChecked(recent.packet_diagram_show && prefs_has_layout_pane_content(layout_pane_content_pdiagram));
|
||||||
|
|
||||||
foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
|
foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
|
||||||
if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp)) {
|
if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc)strcmp)) {
|
||||||
|
@ -2299,6 +2302,9 @@ void MainWindow::showHideMainWidgets(QAction *action)
|
||||||
} else if (widget == byte_view_tab_) {
|
} else if (widget == byte_view_tab_) {
|
||||||
recent.byte_view_show = show;
|
recent.byte_view_show = show;
|
||||||
main_ui_->actionViewPacketBytes->setChecked(show);
|
main_ui_->actionViewPacketBytes->setChecked(show);
|
||||||
|
} else if (widget == packet_diagram_) {
|
||||||
|
recent.packet_diagram_show = show;
|
||||||
|
main_ui_->actionViewPacketDiagram->setChecked(show);
|
||||||
} else {
|
} else {
|
||||||
foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
|
foreach(QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
|
||||||
QToolBar *toolbar = action->data().value<QToolBar *>();
|
QToolBar *toolbar = action->data().value<QToolBar *>();
|
||||||
|
|
|
@ -0,0 +1,736 @@
|
||||||
|
/* packet_diagram.cpp
|
||||||
|
*
|
||||||
|
* Wireshark - Network traffic analyzer
|
||||||
|
* By Gerald Combs <gerald@wireshark.org>
|
||||||
|
* Copyright 1998 Gerald Combs
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "packet_diagram.h"
|
||||||
|
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#include "epan/epan.h"
|
||||||
|
#include "epan/epan_dissect.h"
|
||||||
|
|
||||||
|
#include "wsutil/utf8_entities.h"
|
||||||
|
|
||||||
|
#include "wireshark_application.h"
|
||||||
|
|
||||||
|
#include "ui/qt/main_window.h"
|
||||||
|
#include "ui/qt/utils/proto_node.h"
|
||||||
|
#include "ui/qt/utils/variant_pointer.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <QContextMenuEvent>
|
||||||
|
#include <QGraphicsItem>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#if defined(QT_SVG_LIB) && 0
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QSvgGenerator>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
// "rems" are root em widths, aka the regular font height, similar to rems in CSS.
|
||||||
|
class DiagramLayout {
|
||||||
|
public:
|
||||||
|
DiagramLayout() :
|
||||||
|
bits_per_row_(32),
|
||||||
|
small_font_rems_(0.75),
|
||||||
|
bit_width_rems_(1.0),
|
||||||
|
padding_rems_(0.5),
|
||||||
|
span_mark_offset_rems_(0.2),
|
||||||
|
show_fields_(false)
|
||||||
|
{
|
||||||
|
setFont(wsApp->font());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFont(QFont font) {
|
||||||
|
regular_font_ = font;
|
||||||
|
small_font_ = font;
|
||||||
|
small_font_.setPointSize(regular_font_.pointSize() * small_font_rems_);
|
||||||
|
|
||||||
|
QFontMetrics fm(regular_font_);
|
||||||
|
root_em_ = fm.height();
|
||||||
|
}
|
||||||
|
void setShowFields(bool show_fields = false) { show_fields_ = show_fields; }
|
||||||
|
|
||||||
|
int bitsPerRow() const { return bits_per_row_; }
|
||||||
|
const QFont regularFont() const { return regular_font_; }
|
||||||
|
const QFont smallFont() const { return small_font_; }
|
||||||
|
int bitWidth() const { return root_em_ * bit_width_rems_; }
|
||||||
|
int lineHeight() const { return root_em_; }
|
||||||
|
int hPadding() const { return root_em_ * padding_rems_; }
|
||||||
|
int vPadding() const { return root_em_ * padding_rems_; }
|
||||||
|
int spanMarkOffset() const { return root_em_ * span_mark_offset_rems_; }
|
||||||
|
int rowHeight() const {
|
||||||
|
int rows = show_fields_ ? 2 : 1;
|
||||||
|
return ((lineHeight() * rows) + (vPadding() * 2));
|
||||||
|
}
|
||||||
|
bool showFields() const { return show_fields_; }
|
||||||
|
private:
|
||||||
|
int bits_per_row_;
|
||||||
|
double small_font_rems_;
|
||||||
|
double bit_width_rems_;
|
||||||
|
double padding_rems_;
|
||||||
|
double span_mark_offset_rems_; // XXX Make this padding_rems_ / 2 instead?
|
||||||
|
bool show_fields_;
|
||||||
|
QFont regular_font_;
|
||||||
|
QFont small_font_;
|
||||||
|
int root_em_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FieldInformationGraphicsItem : public QGraphicsPolygonItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FieldInformationGraphicsItem(field_info *fi, int start_bit, int fi_length, const DiagramLayout *layout, QGraphicsItem *parent = nullptr) :
|
||||||
|
QGraphicsPolygonItem(QPolygonF(), parent),
|
||||||
|
finfo_(new FieldInformation(fi)),
|
||||||
|
start_bit_(start_bit),
|
||||||
|
layout_(layout),
|
||||||
|
collapsed_len_(fi_length),
|
||||||
|
collapsed_row_(-1)
|
||||||
|
{
|
||||||
|
Q_ASSERT(layout_);
|
||||||
|
|
||||||
|
for (int idx = 0; idx < NumSpanMarks; idx++) {
|
||||||
|
span_marks_[idx] = new QGraphicsLineItem(this);
|
||||||
|
span_marks_[idx]->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
int bits_per_row = layout_->bitsPerRow();
|
||||||
|
int row1_start = start_bit_ % bits_per_row;
|
||||||
|
int bits_remain = fi_length;
|
||||||
|
|
||||||
|
int row1_bits = bits_remain;
|
||||||
|
if (bits_remain + row1_start > bits_per_row) {
|
||||||
|
row1_bits = bits_per_row - row1_start;
|
||||||
|
bits_remain -= row1_bits;
|
||||||
|
if (row1_start == 0 && bits_remain > bits_per_row) {
|
||||||
|
// Collapse first row
|
||||||
|
bits_remain %= bits_per_row;
|
||||||
|
collapsed_row_ = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bits_remain = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int row2_bits = bits_remain;
|
||||||
|
if (bits_remain > bits_per_row) {
|
||||||
|
row2_bits = bits_per_row;
|
||||||
|
bits_remain -= bits_per_row;
|
||||||
|
if (bits_remain > bits_per_row) {
|
||||||
|
// Collapse second row
|
||||||
|
bits_remain %= bits_per_row;
|
||||||
|
collapsed_row_ = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bits_remain = 0;
|
||||||
|
}
|
||||||
|
int row3_bits = bits_remain;
|
||||||
|
|
||||||
|
collapsed_len_ = row1_bits + row2_bits + row3_bits;
|
||||||
|
|
||||||
|
QRectF rr1, rr2, rr3;
|
||||||
|
QRectF row_rect = QRectF(row1_start, 0, row1_bits, 1);
|
||||||
|
unit_shape_ = QPolygonF(row_rect);
|
||||||
|
rr1 = row_rect;
|
||||||
|
unit_tr_ = row_rect;
|
||||||
|
|
||||||
|
if (row2_bits > 0) {
|
||||||
|
row_rect = QRectF(0, 1, row2_bits, 1);
|
||||||
|
unit_shape_ = unit_shape_.united(QPolygonF(row_rect));
|
||||||
|
rr2 = row_rect;
|
||||||
|
if (row2_bits > row1_bits) {
|
||||||
|
unit_tr_ = row_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row3_bits > 0) {
|
||||||
|
row_rect = QRectF(0, 2, row3_bits, 1);
|
||||||
|
unit_shape_ = unit_shape_.united(QPolygonF(row_rect));
|
||||||
|
rr3 = row_rect;
|
||||||
|
}
|
||||||
|
QPainterPath pp;
|
||||||
|
pp.addPolygon(unit_shape_);
|
||||||
|
unit_shape_ = pp.simplified().toFillPolygon();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLayout();
|
||||||
|
|
||||||
|
if (finfo_->isValid()) {
|
||||||
|
setToolTip(QString("%1 (%2) = %3")
|
||||||
|
.arg(finfo_->headerInfo().name)
|
||||||
|
.arg(finfo_->headerInfo().abbreviation)
|
||||||
|
.arg(finfo_->toString()));
|
||||||
|
setData(Qt::UserRole, VariantPointer<field_info>::asQVariant(finfo_->fieldInfo()));
|
||||||
|
} else {
|
||||||
|
setToolTip(QObject::tr("Gap in dissection"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int collapsedLength() { return collapsed_len_; }
|
||||||
|
|
||||||
|
void setPos(qreal x, qreal y) {
|
||||||
|
QGraphicsPolygonItem::setPos(x, y);
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxLeftY() {
|
||||||
|
qreal rel_len = (start_bit_ % layout_->bitsPerRow()) + collapsed_len_;
|
||||||
|
QPointF pt = mapToParent(QPointF(0, ceil(rel_len / layout_->bitsPerRow()) * layout_->rowHeight()));
|
||||||
|
return pt.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxRightY() {
|
||||||
|
qreal rel_len = (start_bit_ % layout_->bitsPerRow()) + collapsed_len_;
|
||||||
|
QPointF pt = mapToParent(QPointF(0, floor(rel_len / layout_->bitsPerRow()) * layout_->rowHeight()));
|
||||||
|
return pt.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) {
|
||||||
|
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->save();
|
||||||
|
if (!finfo_->isValid()) {
|
||||||
|
QBrush brush = QBrush(option->palette.text().color(), Qt::BDiagPattern);
|
||||||
|
painter->setBrush(brush);
|
||||||
|
} else if (isSelected()) {
|
||||||
|
painter->setBrush(option->palette.highlight().color());
|
||||||
|
}
|
||||||
|
painter->drawPolygon(polygon());
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
// Lower and inner right borders
|
||||||
|
painter->setPen(option->palette.text().color());
|
||||||
|
QPolygonF shape = polygon();
|
||||||
|
for (int idx = 1; idx < unit_shape_.size(); idx++) {
|
||||||
|
QPointF u_start = unit_shape_[idx - 1];
|
||||||
|
QPointF u_end = unit_shape_[idx];
|
||||||
|
QPointF start, end;
|
||||||
|
bool draw_line = false;
|
||||||
|
|
||||||
|
if (u_start.y() > 0 && u_start.y() == u_end.y()) {
|
||||||
|
draw_line = true;
|
||||||
|
} else if (u_start.x() > 0 && u_start.x() < layout_->bitsPerRow() && u_start.x() == u_end.x()) {
|
||||||
|
draw_line = true;
|
||||||
|
}
|
||||||
|
if (draw_line) {
|
||||||
|
start = shape[idx - 1];
|
||||||
|
end = shape[idx];
|
||||||
|
painter->drawLine(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!finfo_->isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field label(s)
|
||||||
|
QString label = finfo_->headerInfo().name;
|
||||||
|
paintLabel(painter, label, scaled_tr_);
|
||||||
|
|
||||||
|
if (layout_->showFields()) {
|
||||||
|
label = finfo_->toString();
|
||||||
|
paintLabel(painter, label, scaled_tr_.adjusted(0, scaled_tr_.height(), 0, scaled_tr_.height()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum SpanMark {
|
||||||
|
TopLeft,
|
||||||
|
BottomLeft,
|
||||||
|
TopRight,
|
||||||
|
BottomRight,
|
||||||
|
NumSpanMarks
|
||||||
|
};
|
||||||
|
FieldInformation *finfo_;
|
||||||
|
int start_bit_;
|
||||||
|
const DiagramLayout *layout_;
|
||||||
|
int collapsed_len_;
|
||||||
|
int collapsed_row_;
|
||||||
|
QPolygonF unit_shape_;
|
||||||
|
QRectF unit_tr_;
|
||||||
|
QRectF scaled_tr_;
|
||||||
|
QGraphicsLineItem *span_marks_[NumSpanMarks];
|
||||||
|
|
||||||
|
void updateLayout() {
|
||||||
|
QTransform xform;
|
||||||
|
|
||||||
|
xform.scale(layout_->bitWidth(), layout_->rowHeight());
|
||||||
|
setPolygon(xform.map(unit_shape_));
|
||||||
|
scaled_tr_ = xform.mapRect(unit_tr_);
|
||||||
|
scaled_tr_.adjust(layout_->hPadding(), layout_->vPadding(), -layout_->hPadding(), -layout_->vPadding());
|
||||||
|
scaled_tr_.setHeight(layout_->lineHeight());
|
||||||
|
|
||||||
|
// Collapsed / span marks
|
||||||
|
for (int idx = 0; idx < NumSpanMarks; idx++) {
|
||||||
|
span_marks_[idx]->hide();
|
||||||
|
}
|
||||||
|
if (collapsed_row_ >= 0) {
|
||||||
|
QRectF bounding_rect = polygon().boundingRect();
|
||||||
|
qreal center_y = bounding_rect.top() + (layout_->rowHeight() * collapsed_row_) + (layout_->rowHeight() / 2);
|
||||||
|
qreal mark_w = layout_->bitWidth() / 3; // Each mark side to center
|
||||||
|
QLineF span_l = QLineF(-mark_w, mark_w / 2, mark_w, -mark_w / 2);
|
||||||
|
for (int idx = 0; idx < NumSpanMarks; idx++) {
|
||||||
|
QPointF center;
|
||||||
|
switch (idx) {
|
||||||
|
case TopLeft:
|
||||||
|
center = QPointF(bounding_rect.left(), center_y - layout_->spanMarkOffset());
|
||||||
|
break;
|
||||||
|
case BottomLeft:
|
||||||
|
center = QPointF(bounding_rect.left(), center_y + layout_->spanMarkOffset());
|
||||||
|
break;
|
||||||
|
case TopRight:
|
||||||
|
center = QPointF(bounding_rect.right(), center_y - layout_->spanMarkOffset());
|
||||||
|
break;
|
||||||
|
case BottomRight:
|
||||||
|
center = QPointF(bounding_rect.right(), center_y + layout_->spanMarkOffset());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
span_marks_[idx]->setLine(span_l.translated(center));
|
||||||
|
span_marks_[idx]->setZValue(zValue() - 0.1);
|
||||||
|
span_marks_[idx]->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintLabel(QPainter *painter, QString label, QRectF label_rect) {
|
||||||
|
QFontMetrics fm = QFontMetrics(layout_->regularFont());
|
||||||
|
|
||||||
|
painter->setFont(layout_->regularFont());
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||||
|
int label_w = fm.horizontalAdvance(label);
|
||||||
|
#else
|
||||||
|
int label_w = fm.width(label);
|
||||||
|
#endif
|
||||||
|
if (label_w > label_rect.width()) {
|
||||||
|
painter->setFont(layout_->smallFont());
|
||||||
|
fm = QFontMetrics(layout_->smallFont());
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||||
|
label_w = fm.horizontalAdvance(label);
|
||||||
|
#else
|
||||||
|
label_w = fm.width(label);
|
||||||
|
#endif
|
||||||
|
if (label_w > label_rect.width()) {
|
||||||
|
// XXX Use parent+ItemClipsChildrenToShape or setScale instead?
|
||||||
|
label = fm.elidedText(label, Qt::ElideRight, label_rect.width());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
painter->drawText(label_rect, Qt::AlignCenter, label);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PacketDiagram::PacketDiagram(QWidget *parent) :
|
||||||
|
QGraphicsView(new QGraphicsScene(), parent),
|
||||||
|
layout_(new DiagramLayout),
|
||||||
|
cap_file_(nullptr),
|
||||||
|
root_node_(nullptr),
|
||||||
|
selected_field_(nullptr),
|
||||||
|
y_pos_(0)
|
||||||
|
{
|
||||||
|
setAccessibleName(tr("Packet diagram"));
|
||||||
|
|
||||||
|
setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
// XXX Move to setMonospaceFont similar to ProtoTree
|
||||||
|
layout_->setFont(font());
|
||||||
|
|
||||||
|
connect(wsApp, &WiresharkApplication::appInitialized, this, &PacketDiagram::connectToMainWindow);
|
||||||
|
QGraphicsScene *this_scene = scene();
|
||||||
|
connect(this_scene, &QGraphicsScene::selectionChanged, this, &PacketDiagram::sceneSelectionChanged);
|
||||||
|
|
||||||
|
connect(wsApp, &WiresharkApplication::zoomRegularFont, this, &PacketDiagram::setFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketDiagram::~PacketDiagram()
|
||||||
|
{
|
||||||
|
delete layout_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::setRootNode(proto_node *root_node)
|
||||||
|
{
|
||||||
|
scene()->clear();
|
||||||
|
root_node_ = root_node;
|
||||||
|
selected_field_ = nullptr;
|
||||||
|
y_pos_ = 0;
|
||||||
|
|
||||||
|
ProtoNode parent_node(root_node_);
|
||||||
|
if (!parent_node.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoNode::ChildIterator kids = parent_node.children();
|
||||||
|
while (kids.element().isValid())
|
||||||
|
{
|
||||||
|
proto_node *tl_node = kids.element().protoNode();
|
||||||
|
kids.next();
|
||||||
|
|
||||||
|
// Exclude all ("Frame") and nothing
|
||||||
|
if (tl_node->finfo->start == 0 && tl_node->finfo->length == (int) tvb_captured_length(cap_file_->edt->tvb)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tl_node->finfo->length < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addDiagram(tl_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::clear()
|
||||||
|
{
|
||||||
|
setRootNode(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::setCaptureFile(capture_file *cf)
|
||||||
|
{
|
||||||
|
// For use by the main view, set the capture file which will later have a
|
||||||
|
// dissection (EDT) ready.
|
||||||
|
// The packet dialog sets a fixed EDT context and MUST NOT use this.
|
||||||
|
cap_file_ = cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::setFont(const QFont &font)
|
||||||
|
{
|
||||||
|
layout_->setFont(font);
|
||||||
|
setRootNode(root_node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::selectedFieldChanged(FieldInformation *finfo)
|
||||||
|
{
|
||||||
|
setSelectedField(finfo ? finfo->fieldInfo() : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::selectedFrameChanged(QList<int> frames)
|
||||||
|
{
|
||||||
|
if (frames.count() == 1 && cap_file_ && cap_file_->edt && cap_file_->edt->tree) {
|
||||||
|
setRootNode(cap_file_->edt->tree);
|
||||||
|
} else {
|
||||||
|
// Clear the proto tree contents as they have become invalid.
|
||||||
|
setRootNode(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::contextMenuEvent(QContextMenuEvent *event)
|
||||||
|
{
|
||||||
|
if (!event) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *action;
|
||||||
|
QMenu ctx_menu(this);
|
||||||
|
|
||||||
|
action = ctx_menu.addAction(tr("Show Field Values"));
|
||||||
|
action->setCheckable(true);
|
||||||
|
action->setChecked(layout_->showFields());
|
||||||
|
connect(action, &QAction::toggled, this, &PacketDiagram::showFieldsToggled);
|
||||||
|
|
||||||
|
ctx_menu.addSeparator();
|
||||||
|
|
||||||
|
action = ctx_menu.addAction(tr("Save Diagram As" UTF8_HORIZONTAL_ELLIPSIS));
|
||||||
|
connect(action, &QAction::triggered, this, &PacketDiagram::saveAsTriggered);
|
||||||
|
|
||||||
|
action = ctx_menu.addAction(tr("Copy as Raster Image"));
|
||||||
|
connect(action, &QAction::triggered, this, &PacketDiagram::copyAsRasterTriggered);
|
||||||
|
|
||||||
|
#if defined(QT_SVG_LIB) && !defined(Q_OS_MAC)
|
||||||
|
action = ctx_menu.addAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as SVG"));
|
||||||
|
connect(action, &QAction::triggered, this, &PacketDiagram::copyAsSvgTriggered);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ctx_menu.exec(event->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::connectToMainWindow()
|
||||||
|
{
|
||||||
|
MainWindow *main_window = qobject_cast<MainWindow *>(wsApp->mainWindow());
|
||||||
|
if (!main_window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connect(main_window, &MainWindow::setCaptureFile, this, &PacketDiagram::setCaptureFile);
|
||||||
|
connect(main_window, &MainWindow::fieldSelected, this, &PacketDiagram::selectedFieldChanged);
|
||||||
|
connect(main_window, &MainWindow::framesSelected, this, &PacketDiagram::selectedFrameChanged);
|
||||||
|
|
||||||
|
connect(this, &PacketDiagram::fieldSelected, main_window, &MainWindow::fieldSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::sceneSelectionChanged()
|
||||||
|
{
|
||||||
|
field_info *sel_fi = nullptr;
|
||||||
|
if (! scene()->selectedItems().isEmpty()) {
|
||||||
|
sel_fi = VariantPointer<field_info>::asPtr(scene()->selectedItems().first()->data(Qt::UserRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel_fi) {
|
||||||
|
FieldInformation finfo(sel_fi, this);
|
||||||
|
emit fieldSelected(&finfo);
|
||||||
|
} else {
|
||||||
|
emit fieldSelected(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WireItem {
|
||||||
|
proto_item *item;
|
||||||
|
int start_bit;
|
||||||
|
int length;
|
||||||
|
};
|
||||||
|
|
||||||
|
void PacketDiagram::addDiagram(proto_node *tl_node)
|
||||||
|
{
|
||||||
|
QGraphicsItem *item;
|
||||||
|
QGraphicsSimpleTextItem *t_item;
|
||||||
|
int bits_per_row = layout_->bitsPerRow();
|
||||||
|
int bit_width = layout_->bitWidth();
|
||||||
|
int diag_w = bit_width * layout_->bitsPerRow();
|
||||||
|
qreal x = layout_->hPadding();
|
||||||
|
|
||||||
|
// Title
|
||||||
|
t_item = scene()->addSimpleText(tl_node->finfo->hfinfo->name);
|
||||||
|
t_item->setFont(layout_->regularFont());
|
||||||
|
t_item->setPos(0, y_pos_);
|
||||||
|
y_pos_ += layout_->lineHeight() + (bit_width / 4);
|
||||||
|
|
||||||
|
int border_top = y_pos_;
|
||||||
|
|
||||||
|
// Bit scale + tick marks
|
||||||
|
QList<int> tick_nums;
|
||||||
|
for (int tn = 0 ; tn < layout_->bitsPerRow(); tn += 16) {
|
||||||
|
tick_nums << tn << tn + 15;
|
||||||
|
}
|
||||||
|
qreal y_bottom = y_pos_ + bit_width;
|
||||||
|
QGraphicsItem *tl_item = scene()->addLine(x, y_bottom, x + diag_w, y_bottom);
|
||||||
|
for (int tick_n = 0; tick_n < bits_per_row; tick_n++) {
|
||||||
|
x = layout_->hPadding() + (tick_n * bit_width);
|
||||||
|
qreal y_top = y_pos_ + (tick_n % 8 == 0 ? 0 : bit_width / 2);
|
||||||
|
if (tick_n > 0) {
|
||||||
|
scene()->addLine(x, y_top, x, y_bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tick_nums.contains(tick_n)) {
|
||||||
|
t_item = scene()->addSimpleText(QString::number(tick_n));
|
||||||
|
t_item->setFont(layout_->smallFont());
|
||||||
|
t_item->setPos(x + ((bit_width - t_item->boundingRect().width()) / 2.0) + 2, y_pos_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y_pos_ = y_bottom;
|
||||||
|
x = layout_->hPadding();
|
||||||
|
|
||||||
|
// Top-level fields
|
||||||
|
int last_start_bit = -1;
|
||||||
|
int max_l_y = y_bottom;
|
||||||
|
QList<WireItem>wire_items;
|
||||||
|
for (proto_item *cur_item = tl_node->first_child; cur_item; cur_item = cur_item->next) {
|
||||||
|
if (proto_item_is_generated(cur_item) || proto_item_is_hidden(cur_item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
field_info *fi = cur_item->finfo;
|
||||||
|
int start_bit = ((fi->start - tl_node->finfo->start) * 8) + FI_GET_BITS_OFFSET(fi);
|
||||||
|
int length = FI_GET_BITS_SIZE(fi) ? FI_GET_BITS_SIZE(fi) : fi->length * 8;
|
||||||
|
|
||||||
|
if (start_bit <= last_start_bit || length <= 0) {
|
||||||
|
qDebug() << "Skipping pass 1" << fi->hfinfo->abbrev << start_bit << last_start_bit << length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
last_start_bit = start_bit;
|
||||||
|
|
||||||
|
WireItem wire_item = { cur_item, start_bit, length };
|
||||||
|
wire_items << wire_item;
|
||||||
|
}
|
||||||
|
qreal z_value = tl_item->zValue();
|
||||||
|
for (int idx = 0; idx < wire_items.size(); idx++) {
|
||||||
|
WireItem *wire_item = &wire_items[idx];
|
||||||
|
field_info *fi = wire_item->item->finfo;
|
||||||
|
|
||||||
|
if (idx < wire_items.size() - 1) {
|
||||||
|
WireItem *next_item = &wire_items[idx + 1];
|
||||||
|
if (wire_item->start_bit + wire_item->length > next_item->start_bit) {
|
||||||
|
wire_item->length = next_item->start_bit - wire_item->start_bit;
|
||||||
|
qDebug() << "Resized pass 2" << fi->hfinfo->abbrev << wire_item->start_bit << wire_item->length << next_item->start_bit;
|
||||||
|
if (wire_item->length <= 0) {
|
||||||
|
qDebug() << "Skipping pass 2" << fi->hfinfo->abbrev << wire_item->start_bit << wire_item->length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_item->start_bit > wire_item->start_bit + wire_item->length) {
|
||||||
|
int gap_start_bit = wire_item->start_bit + wire_item->length;
|
||||||
|
int gap_len = next_item->start_bit - gap_start_bit;
|
||||||
|
int y_off = (gap_start_bit / bits_per_row) * layout_->rowHeight();
|
||||||
|
// Stack each item behind the previous one.
|
||||||
|
z_value -= .01;
|
||||||
|
FieldInformationGraphicsItem *gap_item = new FieldInformationGraphicsItem(nullptr, gap_start_bit, gap_len, layout_);
|
||||||
|
gap_item->setPos(x, y_bottom + y_off);
|
||||||
|
gap_item->setZValue(z_value);
|
||||||
|
scene()->addItem(gap_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int y_off = (wire_item->start_bit / bits_per_row) * layout_->rowHeight();
|
||||||
|
// Stack each item behind the previous one.
|
||||||
|
z_value -= .01;
|
||||||
|
FieldInformationGraphicsItem *fi_item = new FieldInformationGraphicsItem(fi, wire_item->start_bit, wire_item->length, layout_);
|
||||||
|
fi_item->setPos(x, y_bottom + y_off);
|
||||||
|
fi_item->setFlag(QGraphicsItem::ItemIsSelectable);
|
||||||
|
fi_item->setAcceptedMouseButtons(Qt::LeftButton);
|
||||||
|
fi_item->setZValue(z_value);
|
||||||
|
scene()->addItem(fi_item);
|
||||||
|
|
||||||
|
y_pos_ = fi_item->maxRightY();
|
||||||
|
max_l_y = fi_item->maxLeftY();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left & right borders
|
||||||
|
scene()->addLine(x, border_top, x, max_l_y);
|
||||||
|
scene()->addLine(x + diag_w, border_top, x + diag_w, y_pos_);
|
||||||
|
|
||||||
|
// Inter-diagram margin
|
||||||
|
y_pos_ = max_l_y + bit_width;
|
||||||
|
|
||||||
|
// Set the proper color. Needed for dark mode on macOS + Qt 5.15.0 at least, possibly other cases.
|
||||||
|
foreach (item, scene()->items()) {
|
||||||
|
QGraphicsSimpleTextItem *t_item = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(item);
|
||||||
|
if (t_item) {
|
||||||
|
t_item->setBrush(palette().text().color());
|
||||||
|
}
|
||||||
|
QGraphicsLineItem *l_item = qgraphicsitem_cast<QGraphicsLineItem *>(item);
|
||||||
|
if (l_item) {
|
||||||
|
l_item->setPen(palette().text().color());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::setSelectedField(field_info *fi)
|
||||||
|
{
|
||||||
|
QSignalBlocker blocker(this);
|
||||||
|
FieldInformationGraphicsItem *fi_item;
|
||||||
|
|
||||||
|
foreach (QGraphicsItem *item, scene()->items()) {
|
||||||
|
if (item->isSelected()) {
|
||||||
|
item->setSelected(false);
|
||||||
|
fi_item = qgraphicsitem_cast<FieldInformationGraphicsItem *>(item);
|
||||||
|
}
|
||||||
|
if (fi && VariantPointer<field_info>::asPtr(item->data(Qt::UserRole)) == fi) {
|
||||||
|
fi_item = qgraphicsitem_cast<FieldInformationGraphicsItem *>(item);
|
||||||
|
if (fi_item) {
|
||||||
|
fi_item->setSelected(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage PacketDiagram::exportToImage()
|
||||||
|
{
|
||||||
|
// Create a hi-res 2x scaled image.
|
||||||
|
int scale = 2;
|
||||||
|
QRect rr = QRect(0, 0, sceneRect().size().width() * scale, sceneRect().size().height() * scale);
|
||||||
|
QImage raster_diagram = QImage(rr.size(), QImage::Format_ARGB32);
|
||||||
|
QPainter raster_painter(&raster_diagram);
|
||||||
|
|
||||||
|
raster_painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
raster_painter.fillRect(rr, palette().base().color());
|
||||||
|
scene()->render(&raster_painter);
|
||||||
|
|
||||||
|
raster_painter.end();
|
||||||
|
|
||||||
|
return raster_diagram;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(QT_SVG_LIB) && 0
|
||||||
|
QByteArray PacketDiagram::exportToSvg()
|
||||||
|
{
|
||||||
|
QRect sr = QRect(0, 0, sceneRect().size().width(), sceneRect().size().height());
|
||||||
|
QBuffer svg_buf;
|
||||||
|
QSvgGenerator svg_diagram;
|
||||||
|
svg_diagram.setSize(sr.size());
|
||||||
|
svg_diagram.setViewBox(sr);
|
||||||
|
svg_diagram.setOutputDevice(&svg_buf);
|
||||||
|
|
||||||
|
QPainter svg_painter(&svg_diagram);
|
||||||
|
svg_painter.fillRect(sr, palette().base().color());
|
||||||
|
scene()->render(&svg_painter);
|
||||||
|
|
||||||
|
svg_painter.end();
|
||||||
|
|
||||||
|
return svg_buf.buffer();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PacketDiagram::showFieldsToggled(bool checked)
|
||||||
|
{
|
||||||
|
layout_->setShowFields(checked);
|
||||||
|
setRootNode(root_node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX - We have similar code in tcp_stream_dialog and io_graph_dialog. Should this be a common routine?
|
||||||
|
void PacketDiagram::saveAsTriggered()
|
||||||
|
{
|
||||||
|
QString file_name, extension;
|
||||||
|
QDir path(wsApp->lastOpenDir());
|
||||||
|
QString png_filter = tr("Portable Network Graphics (*.png)");
|
||||||
|
QString bmp_filter = tr("Windows Bitmap (*.bmp)");
|
||||||
|
// Gaze upon my beautiful graph with lossy artifacts!
|
||||||
|
QString jpeg_filter = tr("JPEG File Interchange Format (*.jpeg *.jpg)");
|
||||||
|
QStringList fl = QStringList() << png_filter << bmp_filter << jpeg_filter;
|
||||||
|
#if defined(QT_SVG_LIB) && 0
|
||||||
|
QString svg_filter = tr("Scalable Vector Graphics (*.svg)");
|
||||||
|
fl << svg_filter;
|
||||||
|
#endif
|
||||||
|
QString filter = fl.join(";;");
|
||||||
|
|
||||||
|
file_name = WiresharkFileDialog::getSaveFileName(this, wsApp->windowTitleString(tr("Save Graph As" UTF8_HORIZONTAL_ELLIPSIS)),
|
||||||
|
path.canonicalPath(), filter, &extension);
|
||||||
|
|
||||||
|
if (file_name.length() > 0) {
|
||||||
|
bool save_ok = false;
|
||||||
|
if (extension.compare(png_filter) == 0) {
|
||||||
|
QImage raster_diagram = exportToImage();
|
||||||
|
save_ok = raster_diagram.save(file_name, "PNG");
|
||||||
|
} else if (extension.compare(bmp_filter) == 0) {
|
||||||
|
QImage raster_diagram = exportToImage();
|
||||||
|
save_ok = raster_diagram.save(file_name, "BMP");
|
||||||
|
} else if (extension.compare(jpeg_filter) == 0) {
|
||||||
|
QImage raster_diagram = exportToImage();
|
||||||
|
save_ok = raster_diagram.save(file_name, "JPG");
|
||||||
|
}
|
||||||
|
#if defined(QT_SVG_LIB) && 0
|
||||||
|
else if (extension.compare(svg_filter) == 0) {
|
||||||
|
QByteArray svg_diagram = exportToSvg();
|
||||||
|
QFile file(file_name);
|
||||||
|
if (file.open(QIODevice::WriteOnly)) {
|
||||||
|
save_ok = file.write(svg_diagram) > 0;
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// else error dialog?
|
||||||
|
if (save_ok) {
|
||||||
|
path = QDir(file_name);
|
||||||
|
wsApp->setLastOpenDir(path.canonicalPath().toUtf8().constData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDiagram::copyAsRasterTriggered()
|
||||||
|
{
|
||||||
|
QImage raster_diagram = exportToImage();
|
||||||
|
wsApp->clipboard()->setImage(raster_diagram);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(QT_SVG_LIB) && !defined(Q_OS_MAC) && 0
|
||||||
|
void PacketDiagram::copyAsSvgTriggered()
|
||||||
|
{
|
||||||
|
QByteArray svg_ba = exportToSvg();
|
||||||
|
|
||||||
|
// XXX It looks like we have to use/subclass QMacPasteboardMime in
|
||||||
|
// order for this to work on macOS.
|
||||||
|
// It might be easier to just do "Save As" instead.
|
||||||
|
QMimeData *md = new QMimeData();
|
||||||
|
md->setData("image/svg+xml", svg_buf);
|
||||||
|
wsApp->clipboard()->setMimeData(md);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* packet_diagram.h
|
||||||
|
*
|
||||||
|
* Wireshark - Network traffic analyzer
|
||||||
|
* By Gerald Combs <gerald@wireshark.org>
|
||||||
|
* Copyright 1998 Gerald Combs
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PACKET_DIAGRAM_H
|
||||||
|
#define PACKET_DIAGRAM_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <epan/proto.h>
|
||||||
|
|
||||||
|
#include "cfile.h"
|
||||||
|
|
||||||
|
#include <ui/qt/utils/field_information.h>
|
||||||
|
|
||||||
|
#include <QGraphicsView>
|
||||||
|
|
||||||
|
class DiagramLayout;
|
||||||
|
|
||||||
|
class PacketDiagram : public QGraphicsView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PacketDiagram(QWidget *parent = nullptr);
|
||||||
|
~PacketDiagram();
|
||||||
|
void setRootNode(proto_node *root_node);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void fieldSelected(FieldInformation *);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setCaptureFile(capture_file *cf);
|
||||||
|
void setFont(const QFont &font);
|
||||||
|
void selectedFieldChanged(FieldInformation *finfo);
|
||||||
|
void selectedFrameChanged(QList<int> frames);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void contextMenuEvent(QContextMenuEvent *event) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void connectToMainWindow();
|
||||||
|
void sceneSelectionChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addDiagram(proto_node *tl_node);
|
||||||
|
void setSelectedField(field_info *fi);
|
||||||
|
QImage exportToImage();
|
||||||
|
#if defined(QT_SVG_LIB) && 0
|
||||||
|
QByteArray exportToSvg();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void showFieldsToggled(bool checked);
|
||||||
|
void saveAsTriggered();
|
||||||
|
void copyAsRasterTriggered();
|
||||||
|
#if defined(QT_SVG_LIB) && !defined(Q_OS_MAC) && 0
|
||||||
|
void copyAsSvgTriggered();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DiagramLayout *layout_;
|
||||||
|
capture_file *cap_file_;
|
||||||
|
proto_node *root_node_;
|
||||||
|
field_info *selected_field_;
|
||||||
|
int y_pos_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PACKET_DIAGRAM_H
|
|
@ -1823,6 +1823,7 @@ void TCPStreamDialog::transformYRange(const QCPRange &y_range1)
|
||||||
sp->yAxis2->setRangeLower(yp2.y1());
|
sp->yAxis2->setRangeLower(yp2.y1());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX - We have similar code in io_graph_dialog and packet_diagram. Should this be a common routine?
|
||||||
void TCPStreamDialog::on_buttonBox_accepted()
|
void TCPStreamDialog::on_buttonBox_accepted()
|
||||||
{
|
{
|
||||||
QString file_name, extension;
|
QString file_name, extension;
|
||||||
|
|
|
@ -136,16 +136,23 @@ const QString FieldInformation::moduleName()
|
||||||
return module_name;
|
return module_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FieldInformation::toString()
|
||||||
|
{
|
||||||
|
QString repr;
|
||||||
|
gchar *repr_str;
|
||||||
|
repr_str = fvalue_to_string_repr(NULL, &fi_->value, FTREPR_DISPLAY, fi_->hfinfo->display);
|
||||||
|
if (repr_str) {
|
||||||
|
repr = repr_str;
|
||||||
|
}
|
||||||
|
wmem_free(NULL, repr_str);
|
||||||
|
return repr;
|
||||||
|
}
|
||||||
|
|
||||||
QString FieldInformation::url()
|
QString FieldInformation::url()
|
||||||
{
|
{
|
||||||
QString url;
|
QString url;
|
||||||
if (flag(FI_URL) && headerInfo().isValid && IS_FT_STRING(fi_->hfinfo->type)) {
|
if (flag(FI_URL) && headerInfo().isValid && IS_FT_STRING(fi_->hfinfo->type)) {
|
||||||
gchar *url_str;
|
url = toString();
|
||||||
url_str = fvalue_to_string_repr(NULL, &fi_->value, FTREPR_DISPLAY, fi_->hfinfo->display);
|
|
||||||
if (url_str) {
|
|
||||||
url = url_str;
|
|
||||||
}
|
|
||||||
wmem_free(NULL, url_str);
|
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
bool tvbContains(FieldInformation *);
|
bool tvbContains(FieldInformation *);
|
||||||
unsigned flag(unsigned mask);
|
unsigned flag(unsigned mask);
|
||||||
const QString moduleName();
|
const QString moduleName();
|
||||||
|
QString toString();
|
||||||
QString url();
|
QString url();
|
||||||
|
|
||||||
const QByteArray printableData();
|
const QByteArray printableData();
|
||||||
|
|
|
@ -1188,13 +1188,17 @@ void WiresharkApplication::zoomTextFont(int zoomLevel)
|
||||||
{
|
{
|
||||||
// Scale by 10%, rounding to nearest half point, minimum 1 point.
|
// Scale by 10%, rounding to nearest half point, minimum 1 point.
|
||||||
// XXX Small sizes repeat. It might just be easier to create a map of multipliers.
|
// XXX Small sizes repeat. It might just be easier to create a map of multipliers.
|
||||||
zoomed_font_ = mono_font_;
|
|
||||||
qreal zoom_size = mono_font_.pointSize() * 2 * qPow(qreal(1.1), zoomLevel);
|
qreal zoom_size = mono_font_.pointSize() * 2 * qPow(qreal(1.1), zoomLevel);
|
||||||
zoom_size = qRound(zoom_size) / qreal(2.0);
|
zoom_size = qRound(zoom_size) / qreal(2.0);
|
||||||
zoom_size = qMax(zoom_size, qreal(1.0));
|
zoom_size = qMax(zoom_size, qreal(1.0));
|
||||||
zoomed_font_.setPointSizeF(zoom_size);
|
|
||||||
|
|
||||||
|
zoomed_font_ = mono_font_;
|
||||||
|
zoomed_font_.setPointSizeF(zoom_size);
|
||||||
emit zoomMonospaceFont(zoomed_font_);
|
emit zoomMonospaceFont(zoomed_font_);
|
||||||
|
|
||||||
|
QFont zoomed_application_font = font();
|
||||||
|
zoomed_application_font.setPointSizeF(zoom_size);
|
||||||
|
emit zoomRegularFont(zoomed_application_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN)
|
#if defined(HAVE_SOFTWARE_UPDATE) && defined(Q_OS_WIN)
|
||||||
|
|
|
@ -205,6 +205,7 @@ signals:
|
||||||
/* Signals activation and stop of a capture. The value provides the number of active captures */
|
/* Signals activation and stop of a capture. The value provides the number of active captures */
|
||||||
void captureActive(int);
|
void captureActive(int);
|
||||||
|
|
||||||
|
void zoomRegularFont(const QFont & font);
|
||||||
void zoomMonospaceFont(const QFont & font);
|
void zoomMonospaceFont(const QFont & font);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#define RECENT_KEY_PACKET_LIST_SHOW "gui.packet_list_show"
|
#define RECENT_KEY_PACKET_LIST_SHOW "gui.packet_list_show"
|
||||||
#define RECENT_KEY_TREE_VIEW_SHOW "gui.tree_view_show"
|
#define RECENT_KEY_TREE_VIEW_SHOW "gui.tree_view_show"
|
||||||
#define RECENT_KEY_BYTE_VIEW_SHOW "gui.byte_view_show"
|
#define RECENT_KEY_BYTE_VIEW_SHOW "gui.byte_view_show"
|
||||||
|
#define RECENT_KEY_PACKET_DIAGRAM_SHOW "gui.packet_diagram_show"
|
||||||
#define RECENT_KEY_STATUSBAR_SHOW "gui.statusbar_show"
|
#define RECENT_KEY_STATUSBAR_SHOW "gui.statusbar_show"
|
||||||
#define RECENT_KEY_PACKET_LIST_COLORIZE "gui.packet_list_colorize"
|
#define RECENT_KEY_PACKET_LIST_COLORIZE "gui.packet_list_colorize"
|
||||||
#define RECENT_GUI_TIME_FORMAT "gui.time_format"
|
#define RECENT_GUI_TIME_FORMAT "gui.time_format"
|
||||||
|
@ -844,6 +845,10 @@ write_profile_recent(void)
|
||||||
RECENT_KEY_BYTE_VIEW_SHOW,
|
RECENT_KEY_BYTE_VIEW_SHOW,
|
||||||
recent.byte_view_show);
|
recent.byte_view_show);
|
||||||
|
|
||||||
|
write_recent_boolean(rf, "Packet diagram show (hide)",
|
||||||
|
RECENT_KEY_PACKET_DIAGRAM_SHOW,
|
||||||
|
recent.packet_diagram_show);
|
||||||
|
|
||||||
write_recent_boolean(rf, "Statusbar show (hide)",
|
write_recent_boolean(rf, "Statusbar show (hide)",
|
||||||
RECENT_KEY_STATUSBAR_SHOW,
|
RECENT_KEY_STATUSBAR_SHOW,
|
||||||
recent.statusbar_show);
|
recent.statusbar_show);
|
||||||
|
@ -1054,6 +1059,8 @@ read_set_recent_pair_static(gchar *key, const gchar *value,
|
||||||
parse_recent_boolean(value, &recent.tree_view_show);
|
parse_recent_boolean(value, &recent.tree_view_show);
|
||||||
} else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
|
} else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
|
||||||
parse_recent_boolean(value, &recent.byte_view_show);
|
parse_recent_boolean(value, &recent.byte_view_show);
|
||||||
|
} else if (strcmp(key, RECENT_KEY_PACKET_DIAGRAM_SHOW) == 0) {
|
||||||
|
parse_recent_boolean(value, &recent.packet_diagram_show);
|
||||||
} else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
|
} else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
|
||||||
parse_recent_boolean(value, &recent.statusbar_show);
|
parse_recent_boolean(value, &recent.statusbar_show);
|
||||||
} else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
|
} else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
|
||||||
|
@ -1323,6 +1330,7 @@ recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
|
||||||
recent.packet_list_show = TRUE;
|
recent.packet_list_show = TRUE;
|
||||||
recent.tree_view_show = TRUE;
|
recent.tree_view_show = TRUE;
|
||||||
recent.byte_view_show = TRUE;
|
recent.byte_view_show = TRUE;
|
||||||
|
recent.packet_diagram_show = TRUE;
|
||||||
recent.statusbar_show = TRUE;
|
recent.statusbar_show = TRUE;
|
||||||
recent.packet_list_colorize = TRUE;
|
recent.packet_list_colorize = TRUE;
|
||||||
recent.gui_time_format = TS_RELATIVE;
|
recent.gui_time_format = TS_RELATIVE;
|
||||||
|
|
|
@ -89,6 +89,7 @@ typedef struct recent_settings_tag {
|
||||||
gboolean packet_list_show;
|
gboolean packet_list_show;
|
||||||
gboolean tree_view_show;
|
gboolean tree_view_show;
|
||||||
gboolean byte_view_show;
|
gboolean byte_view_show;
|
||||||
|
gboolean packet_diagram_show;
|
||||||
gboolean statusbar_show;
|
gboolean statusbar_show;
|
||||||
gboolean packet_list_colorize;
|
gboolean packet_list_colorize;
|
||||||
ts_type gui_time_format;
|
ts_type gui_time_format;
|
||||||
|
|
Loading…
Reference in New Issue