aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2015-07-29 16:24:39 -0700
committerGerald Combs <gerald@wireshark.org>2015-07-30 19:13:38 +0000
commit16b048d34b51af0ddcfe6dd47865628bcd07223c (patch)
tree356e85b15a51a3418401efe9c90a2b447df4457d
parente482786ae8278377edeb1ac40cb68accdb71451f (diff)
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>
-rw-r--r--ui/qt/byte_view_tab.cpp156
-rw-r--r--ui/qt/byte_view_tab.h16
-rw-r--r--ui/qt/byte_view_text.cpp13
-rw-r--r--ui/qt/byte_view_text.h1
-rw-r--r--ui/qt/main_window.h6
-rw-r--r--ui/qt/main_window.ui36
-rw-r--r--ui/qt/main_window_slots.cpp186
-rw-r--r--ui/qt/packet_list.cpp91
-rw-r--r--ui/qt/packet_list.h2
-rw-r--r--ui/qt/proto_tree.cpp39
-rw-r--r--ui/qt/proto_tree.h1
11 files changed, 437 insertions, 110 deletions
diff --git a/ui/qt/byte_view_tab.cpp b/ui/qt/byte_view_tab.cpp
index 7fcd0a3267..978ef974e9 100644
--- a/ui/qt/byte_view_tab.cpp
+++ b/ui/qt/byte_view_tab.cpp
@@ -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);
diff --git a/ui/qt/byte_view_tab.h b/ui/qt/byte_view_tab.h
index 47151c7c11..31860fb935 100644
--- a/ui/qt/byte_view_tab.h
+++ b/ui/qt/byte_view_tab.h
@@ -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);
diff --git a/ui/qt/byte_view_text.cpp b/ui/qt/byte_view_text.cpp
index c2090701a9..092a2118cd 100644
--- a/ui/qt/byte_view_text.cpp
+++ b/ui/qt/byte_view_text.cpp
@@ -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;
diff --git a/ui/qt/byte_view_text.h b/ui/qt/byte_view_text.h
index 805a0880e8..74898ece49 100644
--- a/ui/qt/byte_view_text.h
+++ b/ui/qt/byte_view_text.h
@@ -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 &);
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index 4a6231d780..cc042a8325 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -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
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index f2c3b09a09..1876ddf73c 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -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">
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index e737e44586..2805d4d1da 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -1147,31 +1147,45 @@ 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;
+ 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;
- 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;
+ 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)) {
+ color_conversation_filter_t* color_filter = (color_conversation_filter_t *)color_list_entry->data;
+ QAction *conv_action = main_ui_->menuConversationFilter->addAction(color_filter->display_name);
+
+ bool enable = false;
+ QString filter;
+ if (capture_file_.capFile()->edt) {
+ enable = color_filter->is_filter_valid(&capture_file_.capFile()->edt->pi);
+ filter = color_filter->build_filter_string(&capture_file_.capFile()->edt->pi);
+ }
+ conv_action->setEnabled(enable);
+ conv_action->setData(filter);
+ connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter()));
}
- 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);
@@ -1188,16 +1202,9 @@ void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
// 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",
@@ -1207,41 +1214,6 @@ void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
// 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);
-
- 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)) {
- color_conversation_filter_t* color_filter = (color_conversation_filter_t *)color_list_entry->data;
- QAction *conv_action = main_ui_->menuConversationFilter->addAction(color_filter->display_name);
-
- bool enable = false;
- QString filter;
- if (capture_file_.capFile()->edt) {
- enable = color_filter->is_filter_valid(&capture_file_.capFile()->edt->pi);
- filter = color_filter->build_filter_string(&capture_file_.capFile()->edt->pi);
- }
- conv_action->setEnabled(enable);
- conv_action->setData(filter);
- connect(conv_action, SIGNAL(triggered()), this, SLOT(applyConversationFilter()));
- }
-
- main_ui_->actionViewExpandSubtrees->setEnabled(capture_file_.capFile()->finfo_selected->tree_type != -1);
-
- } 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
*
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index a2d768f900..bc1764831a 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -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)
diff --git a/ui/qt/packet_list.h b/ui/qt/packet_list.h
index d7061bde79..a8d2658577 100644
--- a/ui/qt/packet_list.h
+++ b/ui/qt/packet_list.h
@@ -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();
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index 7dc9048bf8..2034caa4f7 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -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());
}
diff --git a/ui/qt/proto_tree.h b/ui/qt/proto_tree.h
index 4bef897fff..ad21111936 100644
--- a/ui/qt/proto_tree.h
+++ b/ui/qt/proto_tree.h
@@ -51,6 +51,7 @@ private:
QMenu conv_menu_;
ProtocolPreferencesMenu proto_prefs_menu_;
QAction *decode_as_;
+ QList<QAction *> copy_actions_;
QFont mono_font_;
signals: