Packet list and detail context menu updates.

Add some missing items to the packet list and detail "Copy" context
menus. Don't nest the "Copy" items so deeply. Add YAML to the supported
summary formats.

Note that "Copy as Binary" copies to the clipboard as
application/octet-stream, which is a) arguably correct, and b) not very
useful. Fixes welcome.

Enable and disable packet detail context menu items from a set of
booleans similar to the packet list.

Change-Id: Iaa931c766aa476c33f27de089e5c4dbaf9ce74d6
Ping-Bug: 9320
Bug: 10831
Reviewed-on: https://code.wireshark.org/review/9825
Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
Gerald Combs 2015-07-29 16:24:39 -07:00
parent e482786ae8
commit 16b048d34b
11 changed files with 451 additions and 124 deletions

View File

@ -21,6 +21,10 @@
#include "byte_view_tab.h"
#include "byte_view_text.h"
#include <QApplication>
#include <QClipboard>
#include <QMimeData>
#include <QTabBar>
#include <QTreeWidgetItem>
@ -62,6 +66,158 @@ void ByteViewTab::clear()
setVisible(visible);
}
// XXX How many hex dump routines do we have?
const int byte_line_length_ = 16; // Print out data for 16 bytes on one line
void ByteViewTab::copyHexTextDump(const guint8 *data_p, int data_len, bool append_text)
{
QString clipboard_text;
/* Write hex data for a line, then ascii data, then concatenate and add to buffer */
QString hex_str, char_str;
int i;
bool end_of_line = true; /* Initial state is end of line */
int byte_line_part_length;
i = 0;
while (i < data_len) {
if(end_of_line) {
hex_str += QString("%1 ").arg(i, 4, 16, QChar('0')); /* Offset - note that we _append_ here */
}
hex_str += QString(" %1").arg(*data_p, 2, 16, QChar('0'));
if(append_text) {
char_str += QString("%1").arg(g_ascii_isprint(*data_p) ? QChar(*data_p) : '.');
}
++data_p;
/* Look ahead to see if this is the end of the data */
byte_line_part_length = (++i) % byte_line_length_;
if(i >= data_len){
/* End of data - need to fill in spaces in hex string and then do "end of line".
*
*/
if (append_text) {
int fill_len = byte_line_part_length == 0 ?
0 : byte_line_length_ - byte_line_part_length;
/* Add three spaces for each missing byte */
hex_str += QString(fill_len * 3, ' ');
}
end_of_line = true;
} else {
end_of_line = (byte_line_part_length == 0);
}
if (end_of_line){
/* End of line */
clipboard_text += hex_str;
if(append_text) {
/* Two spaces between hex and text */
clipboard_text += " ";
clipboard_text += char_str;
}
/* Setup ready for next line */
hex_str = "\n";
char_str.clear();
}
}
if (!clipboard_text.isEmpty()) {
qApp->clipboard()->setText(clipboard_text);
}
}
void ByteViewTab::copyPrintableText(const guint8 *data_p, int data_len)
{
QString clipboard_text;
for (int i = 0; i < data_len; i++) {
const guint8 c = data_p[i];
if (g_ascii_isprint(c) || g_ascii_isspace(c)) {
clipboard_text += QChar(c);
}
}
if (!clipboard_text.isEmpty()) {
qApp->clipboard()->setText(clipboard_text);
}
}
void ByteViewTab::copyHexStream(const guint8 *data_p, int data_len)
{
QString clipboard_text;
for (int i = 0; i < data_len; i++) {
clipboard_text += QString("%1").arg(data_p[i], 2, 16, QChar('0'));
}
if (!clipboard_text.isEmpty()) {
qApp->clipboard()->setText(clipboard_text);
}
}
void ByteViewTab::copyBinary(const guint8 *data_p, int data_len)
{
QByteArray clipboard_bytes = QByteArray::fromRawData((const char *) data_p, data_len);
if (!clipboard_bytes.isEmpty()) {
QMimeData mime_data;
// gtk/gui_utils.c:copy_binary_to_clipboard says:
/* XXX - this is not understood by most applications,
* but can be pasted into the better hex editors - is
* there something better that we can do?
*/
mime_data.setData("application/octet-stream", clipboard_bytes);
qApp->clipboard()->setMimeData(&mime_data);
}
}
void ByteViewTab::copyData(ByteViewTab::copyDataType copy_type, field_info *fi)
{
int i = 0;
ByteViewText *byte_view_text = qobject_cast<ByteViewText*>(widget(i));
if (fi) {
while (byte_view_text) {
if (byte_view_text->hasDataSource(fi->ds_tvb)) break;
byte_view_text = qobject_cast<ByteViewText*>(widget(++i));
}
}
if (!byte_view_text) return;
guint data_len = 0;
const guint8 *data_p;
data_p = byte_view_text->dataAndLength(&data_len);
if (!data_p) return;
if (fi && fi->start >= 0 && fi->length > 0 && fi->length <= (int) data_len) {
data_len = fi->length;
data_p += fi->start;
}
if (!data_len) return;
switch (copy_type) {
case copyDataHexTextDump:
copyHexTextDump(data_p, data_len, true);
break;
case copyDataHexDump:
copyHexTextDump(data_p, data_len, false);
break;
case copyDataPrintableText:
copyPrintableText(data_p, data_len);
break;
case copyDataHexStream:
copyHexStream(data_p, data_len);
break;
case copyDataBinary:
copyBinary(data_p, data_len);
break;
default:
break;
}
}
void ByteViewTab::tabInserted(int index) {
setTabsVisible();
QTabWidget::tabInserted(index);

View File

@ -39,15 +39,29 @@ class ByteViewTab : public QTabWidget
{
Q_OBJECT
public:
enum copyDataType {
copyDataHexTextDump,
copyDataHexDump,
copyDataPrintableText,
copyDataHexStream,
copyDataBinary
};
explicit ByteViewTab(QWidget *parent = 0);
void addTab(const char *name = "", tvbuff_t *tvb = NULL, proto_tree *tree = NULL, QTreeWidget *protoTree = NULL, packet_char_enc encoding = PACKET_CHAR_ENC_CHAR_ASCII);
void clear();
void copyData(copyDataType copy_type, field_info *fi = NULL);
private:
void setTabsVisible();
capture_file *cap_file_;
QFont mono_font_;
void setTabsVisible();
void copyHexTextDump(const guint8 *data_p, int data_len, bool append_text);
void copyPrintableText(const guint8 *data_p, int data_len);
void copyHexStream(const guint8 *data_p, int data_len);
void copyBinary(const guint8 *data_p, int data_len);
protected:
void tabInserted(int index);
void tabRemoved(int index);

View File

@ -38,6 +38,7 @@
// - Add recent settings and context menu items to show/hide the offset,
// hex/bits, and ASCII/EBCDIC.
// - Add a UTF-8 and possibly UTF-xx option to the ASCII display.
// - Add "copy bytes as" context menu items.
// We don't obey the gui.hex_dump_highlight_style preference. If you
// would like to add support for this you'll probably have to call
@ -114,6 +115,18 @@ void ByteViewText::setFieldAppendixHighlight(int start, int end)
viewport()->update();
}
const guint8 *ByteViewText::dataAndLength(guint *data_len_ptr)
{
if (!tvb_) return NULL;
guint data_len = tvb_captured_length(tvb_);
if (data_len) {
*data_len_ptr = data_len;
return tvb_get_ptr(tvb_, 0, -1);
}
return NULL;
}
void ByteViewText::setMonospaceFont(const QFont &mono_font)
{
mono_font_ = mono_font;

View File

@ -56,6 +56,7 @@ public:
void setFieldHighlight(int start, int end, guint32 mask = 0, int mask_le = 0);
void setFieldAppendixHighlight(int start, int end);
bool isEmpty() { return tvb_ == NULL || proto_tree_ == NULL; }
const guint8 *dataAndLength(guint *data_len_ptr);
signals:
void byteFieldHovered(const QString &);

View File

@ -525,6 +525,12 @@ private slots:
void externalMenuItem_triggered();
void on_actionContextCopyBytesHexTextDump_triggered();
void on_actionContextCopyBytesHexDump_triggered();
void on_actionContextCopyBytesPrintableText_triggered();
void on_actionContextCopyBytesHexStream_triggered();
void on_actionContextCopyBytesBinary_triggered();
void changeEvent(QEvent* event);
#if HAVE_EXTCAP

View File

@ -2285,24 +2285,44 @@
<string>Show or hide the packet bytes</string>
</property>
</action>
<action name="actionFollow">
<action name="actionContextCopyBytesHexTextDump">
<property name="text">
<string>Follow...</string>
<string>Copy Bytes as Hex + ASCII Dump</string>
</property>
<property name="toolTip">
<string>Copy packet bytes as a hex and ASCII dump.</string>
</property>
</action>
<action name="actionSCTP">
<action name="actionContextCopyBytesHexDump">
<property name="text">
<string>SCTP</string>
<string>…as Hex Dump</string>
</property>
<property name="toolTip">
<string>Copy packet bytes as a hex dump.</string>
</property>
</action>
<action name="actionCopy">
<action name="actionContextCopyBytesPrintableText">
<property name="text">
<string>Copy</string>
<string>…as Printable Text</string>
</property>
<property name="toolTip">
<string>Copy only the printable text in the packet.</string>
</property>
</action>
<action name="actionBytes">
<action name="actionContextCopyBytesHexStream">
<property name="text">
<string>Bytes</string>
<string>…as a Hex Stream</string>
</property>
<property name="toolTip">
<string>Copy packet bytes as a stream of hex.</string>
</property>
</action>
<action name="actionContextCopyBytesBinary">
<property name="text">
<string>…as Raw Binary</string>
</property>
<property name="toolTip">
<string>Copy packet bytes as application/octet-stream MIME data.</string>
</property>
</action>
<action name="actionTelephonyVoipCalls">

View File

@ -1147,81 +1147,25 @@ void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
// a result of a packet list selection. Don't assume control of the menu.
if (!proto_tree_ || !proto_tree_->hasFocus()) return;
bool can_match_selected = false;
bool is_framenum = false;
bool have_field_info = false;
bool have_subtree = false;
if (capture_file_.capFile()) {
capture_file_.capFile()->finfo_selected = fi;
if (fi && fi->tree_type != -1) {
have_subtree = true;
}
}
if (capture_file_.capFile() != NULL && fi != NULL) {
header_field_info *hfinfo = capture_file_.capFile()->finfo_selected->hfinfo;
/*
const char *abbrev;
char *prev_abbrev;
if (hfinfo->parent == -1) {
abbrev = hfinfo->abbrev;
id = (hfinfo->type == FT_PROTOCOL) ? proto_get_id((protocol_t *)hfinfo->strings) : -1;
} else {
abbrev = proto_registrar_get_abbrev(hfinfo->parent);
id = hfinfo->parent;
}
properties = prefs_is_registered_protocol(abbrev);
*/
bool can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt);
bool is_framenum = hfinfo && hfinfo->type == FT_FRAMENUM ? true : false;
// set_menu_sensitivity(ui_manager_tree_view_menu,
// "/TreeViewPopup/GotoCorrespondingPacket", hfinfo->type == FT_FRAMENUM);
main_ui_->actionViewShowPacketReferenceInNewWindow->setEnabled(is_framenum);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/Copy",
// TRUE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/CreateAColumn",
// hfinfo->type != FT_NONE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ColorizewithFilter",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/DisableProtocol",
// (id == -1) ? FALSE : proto_can_toggle_protocol(id));
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ExpandSubtrees",
// cf->finfo_selected->tree_type != -1);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/WikiProtocolPage",
// (id == -1) ? FALSE : TRUE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/FilterFieldReference",
// (id == -1) ? FALSE : TRUE);
// set_menu_sensitivity(ui_manager_main_menubar,
main_ui_->actionFileExportPacketBytes->setEnabled(true);
// set_menu_sensitivity(ui_manager_main_menubar,
// "/Menubar/GoMenu/GotoCorrespondingPacket", hfinfo->type == FT_FRAMENUM);
main_ui_->actionCopyAllVisibleItems->setEnabled(true);
main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
main_ui_->actionEditCopyValue->setEnabled(can_match_selected);
main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected);
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/Description",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/Fieldname",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/Value",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/AsFilter",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
main_ui_->actionAnalyzeCreateAColumn->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFAndSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFOrSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFAndSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFOrSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(can_match_selected);
have_field_info = true;
can_match_selected = proto_can_match_selected(capture_file_.capFile()->finfo_selected, capture_file_.capFile()->edt);
is_framenum = hfinfo && hfinfo->type == FT_FRAMENUM ? true : false;
main_ui_->menuConversationFilter->clear();
for (GList *color_list_entry = color_conv_filter_list; color_list_entry; color_list_entry = g_list_next(color_list_entry)) {
@ -1238,10 +1182,38 @@ void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
conv_action->setData(filter);
connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter()));
}
}
main_ui_->actionViewExpandSubtrees->setEnabled(capture_file_.capFile()->finfo_selected->tree_type != -1);
// set_menu_sensitivity(ui_manager_tree_view_menu,
// "/TreeViewPopup/GotoCorrespondingPacket", hfinfo->type == FT_FRAMENUM);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/Copy",
// TRUE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/CreateAColumn",
// hfinfo->type != FT_NONE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ColorizewithFilter",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/DisableProtocol",
// (id == -1) ? FALSE : proto_can_toggle_protocol(id));
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/ExpandSubtrees",
// cf->finfo_selected->tree_type != -1);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/WikiProtocolPage",
// (id == -1) ? FALSE : TRUE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/FilterFieldReference",
// (id == -1) ? FALSE : TRUE);
// set_menu_sensitivity(ui_manager_main_menubar,
// set_menu_sensitivity(ui_manager_main_menubar,
// "/Menubar/GoMenu/GotoCorrespondingPacket", hfinfo->type == FT_FRAMENUM);
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/Description",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/Fieldname",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/Value",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/EditMenu/Copy/AsFilter",
// proto_can_match_selected(cf->finfo_selected, cf->edt));
} else {
// set_menu_sensitivity(ui_manager_tree_view_menu,
// "/TreeViewPopup/GotoCorrespondingPacket", FALSE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/Copy", FALSE);
@ -1256,37 +1228,37 @@ void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
// FALSE);
// set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/FilterFieldReference",
// FALSE);
main_ui_->actionFileExportPacketBytes->setEnabled(false);
// set_menu_sensitivity(ui_manager_main_menubar,
// "/Menubar/GoMenu/GotoCorrespondingPacket", FALSE);
if (capture_file_.capFile() != NULL)
main_ui_->actionCopyAllVisibleItems->setEnabled(true);
else
main_ui_->actionCopyAllVisibleItems->setEnabled(false);
main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(false);
main_ui_->actionEditCopyDescription->setEnabled(false);
main_ui_->actionEditCopyFieldName->setEnabled(false);
main_ui_->actionEditCopyValue->setEnabled(false);
main_ui_->actionEditCopyAsFilter->setEnabled(false);
main_ui_->actionAnalyzeCreateAColumn->setEnabled(false);
main_ui_->actionFileExportPacketBytes->setEnabled(have_field_info);
main_ui_->actionViewShowPacketReferenceInNewWindow->setEnabled(is_framenum);
main_ui_->actionAnalyzeAAFSelected->setEnabled(false);
main_ui_->actionAnalyzeAAFNotSelected->setEnabled(false);
main_ui_->actionAnalyzeAAFAndSelected->setEnabled(false);
main_ui_->actionAnalyzeAAFOrSelected->setEnabled(false);
main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(false);
main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(false);
main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL);
main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFSelected->setEnabled(false);
main_ui_->actionAnalyzePAFNotSelected->setEnabled(false);
main_ui_->actionAnalyzePAFAndSelected->setEnabled(false);
main_ui_->actionAnalyzePAFOrSelected->setEnabled(false);
main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(false);
main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(false);
main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
main_ui_->actionEditCopyValue->setEnabled(can_match_selected);
main_ui_->actionEditCopyAsFilter->setEnabled(can_match_selected);
main_ui_->actionViewExpandSubtrees->setEnabled(false);
}
main_ui_->actionAnalyzeCreateAColumn->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFAndSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFOrSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFAndNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzeAAFOrNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFAndSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFOrSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFAndNotSelected->setEnabled(can_match_selected);
main_ui_->actionAnalyzePAFOrNotSelected->setEnabled(can_match_selected);
main_ui_->actionViewExpandSubtrees->setEnabled(have_subtree);
}
void MainWindow::interfaceSelectionChanged()
@ -3278,6 +3250,58 @@ void MainWindow::showExtcapOptionsDialog(QString &device_name)
}
#endif
// Q_DECLARE_METATYPE(field_info *) called in proto_tree.h
void MainWindow::on_actionContextCopyBytesHexTextDump_triggered()
{
QAction *ca = qobject_cast<QAction*>(sender());
if (!ca) return;
field_info *fi = ca->data().value<field_info *>();
byte_view_tab_->copyData(ByteViewTab::copyDataHexTextDump, fi);
}
void MainWindow::on_actionContextCopyBytesHexDump_triggered()
{
QAction *ca = qobject_cast<QAction*>(sender());
if (!ca) return;
field_info *fi = ca->data().value<field_info *>();
byte_view_tab_->copyData(ByteViewTab::copyDataHexDump, fi);
}
void MainWindow::on_actionContextCopyBytesPrintableText_triggered()
{
QAction *ca = qobject_cast<QAction*>(sender());
if (!ca) return;
field_info *fi = ca->data().value<field_info *>();
byte_view_tab_->copyData(ByteViewTab::copyDataPrintableText, fi);
}
void MainWindow::on_actionContextCopyBytesHexStream_triggered()
{
QAction *ca = qobject_cast<QAction*>(sender());
if (!ca) return;
field_info *fi = ca->data().value<field_info *>();
byte_view_tab_->copyData(ByteViewTab::copyDataHexStream, fi);
}
void MainWindow::on_actionContextCopyBytesBinary_triggered()
{
QAction *ca = qobject_cast<QAction*>(sender());
if (!ca) return;
field_info *fi = ca->data().value<field_info *>();
byte_view_tab_->copyData(ByteViewTab::copyDataBinary, fi);
}
/*
* Editor modelines
*

View File

@ -59,6 +59,7 @@
#include <QAction>
#include <QActionGroup>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QtCore/qmath.h>
#include <QElapsedTimer>
@ -225,10 +226,16 @@ packet_list_recent_write_all(FILE *rf) {
gbl_cur_packet_list->writeRecent(rf);
}
#define MIN_COL_WIDTH_STR "...."
#define MIN_COL_WIDTH_STR "MMMMMM"
Q_DECLARE_METATYPE(PacketList::ColumnActions)
enum copy_summary_type {
copy_summary_text_,
copy_summary_csv_,
copy_summary_yaml_
};
PacketList::PacketList(QWidget *parent) :
QTreeView(parent),
proto_tree_(NULL),
@ -242,7 +249,7 @@ PacketList::PacketList(QWidget *parent) :
tail_timer_id_(0),
rows_inserted_(false)
{
QMenu *main_menu_item, *submenu, *subsubmenu;
QMenu *main_menu_item, *submenu;
QAction *action;
setItemsExpandable(false);
@ -328,17 +335,36 @@ PacketList::PacketList(QWidget *parent) :
ctx_menu_.addSeparator();
action = window()->findChild<QAction *>("actionCopy");
submenu = new QMenu(action->text());
main_menu_item = window()->findChild<QMenu *>("menuEditCopy");
submenu = new QMenu(main_menu_item->title());
ctx_menu_.addMenu(submenu);
// " <menuitem name='SummaryTxt' action='/Copy/SummaryTxt'/>\n"
// " <menuitem name='SummaryCSV' action='/Copy/SummaryCSV'/>\n"
submenu->addAction(window()->findChild<QAction *>("actionEditCopyAsFilter"));
action = submenu->addAction(tr("Summary (Text)"));
action->setData(copy_summary_text_);
connect(action, SIGNAL(triggered()), this, SLOT(copySummary()));
action = submenu->addAction(tr("Summary (CSV)"));
action->setData(copy_summary_csv_);
connect(action, SIGNAL(triggered()), this, SLOT(copySummary()));
action = submenu->addAction(tr("Summary (YAML)"));
action->setData(copy_summary_yaml_);
connect(action, SIGNAL(triggered()), this, SLOT(copySummary()));
submenu->addSeparator();
action = window()->findChild<QAction *>("actionBytes");
subsubmenu = new QMenu(action->text());
submenu->addMenu(subsubmenu);
action = window()->findChild<QAction *>("actionContextCopyBytesHexTextDump");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesHexDump");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesPrintableText");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesHexStream");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesBinary");
submenu->addAction(action);
copy_actions_ << action;
// " <menuitem name='OffsetHexText' action='/Copy/Bytes/OffsetHexText'/>\n"
// " <menuitem name='OffsetHex' action='/Copy/Bytes/OffsetHex'/>\n"
@ -488,11 +514,14 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
}
proto_prefs_menu_.setModule(module_name);
foreach (QAction *action, copy_actions_) {
action->setData(QVariant());
}
decode_as_->setData(qVariantFromValue(true));
ctx_column_ = columnAt(event->x());
// Set menu sensitivity for the current column and fill in conversation
// actions.
// Set menu sensitivity for the current column and set action data.
emit packetSelectionChanged();
ctx_menu_.exec(event->globalPos());
@ -1179,6 +1208,44 @@ void PacketList::sectionMoved(int, int, int)
wsApp->emitAppSignal(WiresharkApplication::ColumnsChanged);
}
void PacketList::copySummary()
{
if (!currentIndex().isValid()) return;
QAction *ca = qobject_cast<QAction*>(sender());
if (!ca) return;
bool ok = false;
int copy_type = ca->data().toInt(&ok);
if (!ok) return;
QStringList col_parts;
int row = currentIndex().row();
for (int col = 0; col < packet_list_model_->columnCount(); col++) {
col_parts << packet_list_model_->data(packet_list_model_->index(row, col), Qt::DisplayRole).toString();
}
QString copy_text;
switch (copy_type) {
case copy_summary_csv_:
copy_text = "\"";
copy_text += col_parts.join("\",\"");
copy_text += "\"";
break;
case copy_summary_yaml_:
copy_text = "----\n";
copy_text += QString("# Packet %1 from %2\n").arg(row).arg(cap_file_->filename);
copy_text += "- ";
copy_text += col_parts.join("\n- ");
copy_text += "\n";
break;
case copy_summary_text_:
default:
copy_text = col_parts.join("\t");
}
wsApp->clipboard()->setText(copy_text);
}
// We need to tell when the user has scrolled the packet list, either to
// the end or anywhere other than the end.
void PacketList::vScrollBarActionTriggered(int)

View File

@ -96,6 +96,7 @@ private:
QMenu colorize_menu_;
ProtocolPreferencesMenu proto_prefs_menu_;
QAction *decode_as_;
QList<QAction *> copy_actions_;
int ctx_column_;
QByteArray column_state_;
OverlayScrollBar *overlay_sb_;
@ -155,6 +156,7 @@ private slots:
void columnVisibilityTriggered();
void sectionResized(int col, int, int new_width);
void sectionMoved(int, int, int);
void copySummary();
void vScrollBarActionTriggered(int);
void drawFarOverlay();
void drawNearOverlay();

View File

@ -164,7 +164,7 @@ ProtoTree::ProtoTree(QWidget *parent) :
// Assume we're a child of the main window.
// XXX We might want to reimplement setParent() and fill in the context
// menu there.
QMenu *main_menu_item, *submenu, *subsubmenu;
QMenu *main_menu_item, *submenu;
QAction *action;
ctx_menu_.addAction(window()->findChild<QAction *>("actionViewExpandSubtrees"));
@ -221,9 +221,10 @@ ProtoTree::ProtoTree(QWidget *parent) :
// " <menuitem name='FollowSSLStream' action='/Follow SSL Stream'/>\n"
ctx_menu_.addSeparator();
action = window()->findChild<QAction *>("actionCopy");
submenu = new QMenu(action->text());
main_menu_item = window()->findChild<QMenu *>("menuEditCopy");
submenu = new QMenu(main_menu_item->title());
ctx_menu_.addMenu(submenu);
submenu->addAction(window()->findChild<QAction *>("actionCopyAllVisibleItems"));
submenu->addAction(window()->findChild<QAction *>("actionCopyAllVisibleSelectedTreeItems"));
submenu->addAction(window()->findChild<QAction *>("actionEditCopyDescription"));
@ -232,10 +233,24 @@ ProtoTree::ProtoTree(QWidget *parent) :
submenu->addSeparator();
submenu->addAction(window()->findChild<QAction *>("actionEditCopyAsFilter"));
action = window()->findChild<QAction *>("actionBytes");
subsubmenu = new QMenu(action->text());
submenu->addMenu(subsubmenu);
subsubmenu->addSeparator();
submenu->addSeparator();
action = window()->findChild<QAction *>("actionContextCopyBytesHexTextDump");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesHexDump");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesPrintableText");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesHexStream");
submenu->addAction(action);
copy_actions_ << action;
action = window()->findChild<QAction *>("actionContextCopyBytesBinary");
submenu->addAction(action);
copy_actions_ << action;
// " <menu name= 'Bytes' action='/Copy/Bytes'>\n"
// " <menuitem name='OffsetHexText' action='/Copy/Bytes/OffsetHexText'/>\n"
// " <menuitem name='OffsetHex' action='/Copy/Bytes/OffsetHex'/>\n"
@ -290,9 +305,10 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
conv_menu_.addAction(action);
}
field_info *fi = NULL;
const char *module_name = NULL;
if (selectedItems().count() > 0) {
field_info *fi = selectedItems()[0]->data(0, Qt::UserRole).value<field_info *>();
fi = selectedItems()[0]->data(0, Qt::UserRole).value<field_info *>();
if (fi && fi->hfinfo) {
if (fi->hfinfo->parent == -1) {
module_name = fi->hfinfo->abbrev;
@ -303,7 +319,14 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event)
}
proto_prefs_menu_.setModule(module_name);
foreach (QAction *action, copy_actions_) {
action->setData(QVariant::fromValue<field_info *>(fi));
}
decode_as_->setData(qVariantFromValue(true));
// Set menu sensitivity and action data.
emit protoItemSelected(fi);
ctx_menu_.exec(event->globalPos());
decode_as_->setData(QVariant());
}

View File

@ -51,6 +51,7 @@ private:
QMenu conv_menu_;
ProtocolPreferencesMenu proto_prefs_menu_;
QAction *decode_as_;
QList<QAction *> copy_actions_;
QFont mono_font_;
signals: