aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/qt/protocol_hierarchy_dialog.cpp131
-rw-r--r--ui/qt/protocol_hierarchy_dialog.h7
-rw-r--r--ui/qt/protocol_hierarchy_dialog.ui16
3 files changed, 144 insertions, 10 deletions
diff --git a/ui/qt/protocol_hierarchy_dialog.cpp b/ui/qt/protocol_hierarchy_dialog.cpp
index 86c828b600..833029ce8b 100644
--- a/ui/qt/protocol_hierarchy_dialog.cpp
+++ b/ui/qt/protocol_hierarchy_dialog.cpp
@@ -29,10 +29,11 @@
#include "qt_ui_utils.h"
#include "wireshark_application.h"
-#include <QRect>
+#include <QClipboard>
#include <QPainter>
-#include <QTreeWidget>
-#include <QTreeWidgetItem>
+#include <QPushButton>
+#include <QTextStream>
+#include <QTreeWidgetItemIterator>
/*
* @file Protocol Hierarchy Statistics dialog
@@ -42,7 +43,7 @@
*/
// To do:
-// - Copy as... YAML?
+// - Make "Copy as YAML" output a tree?
// - Add time series data to ph_stats_node_t and draw sparklines.
const int protocol_col_ = 0;
@@ -55,8 +56,6 @@ const int end_packets_col_ = 6;
const int end_bytes_col_ = 7;
const int end_bandwidth_col_ = 8;
-#include <QDebug>
-
const int bar_em_width_ = 8;
const double bar_blend_ = 0.15;
void PercentBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -85,7 +84,7 @@ void PercentBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
cg = QPalette::Inactive;
if (optv4.state & QStyle::State_Selected) {
painter->setPen(optv4.palette.color(cg, QPalette::HighlightedText));
- bar_color = ColorUtils::alphaBlend(optv4.palette.color(cg, QPalette::HighlightedText),
+ bar_color = ColorUtils::alphaBlend(optv4.palette.color(cg, QPalette::Window),
optv4.palette.color(cg, QPalette::Highlight),
bar_blend_);
} else {
@@ -144,15 +143,42 @@ public:
setText(protocol_col_, ph_stats_node->hfinfo->name);
setData(pct_packets_col_, Qt::UserRole, percent_packets_);
- setText(packets_col_, QString::number(ph_stats_node->num_pkts_total));
+ setText(packets_col_, QString::number(total_packets_));
setData(pct_bytes_col_, Qt::UserRole, percent_bytes_);
- setText(bytes_col_, QString::number(ph_stats_node->num_bytes_total));
+ setText(bytes_col_, QString::number(total_bytes_));
setText(bandwidth_col_, seconds > 0.0 ? bits_s_to_qstring(bits_s_) : UTF8_EM_DASH);
setText(end_packets_col_, QString::number(last_packets_));
setText(end_bytes_col_, QString::number(last_bytes_));
setText(end_bandwidth_col_, seconds > 0.0 ? bits_s_to_qstring(end_bits_s_) : UTF8_EM_DASH);
}
+ // Return a QString, int, double, or invalid QVariant representing the raw column data.
+ QVariant colData(int col) const {
+ switch(col) {
+ case protocol_col_:
+ return text(col);
+ case (pct_packets_col_):
+ return percent_packets_;
+ case (packets_col_):
+ return total_packets_;
+ case (pct_bytes_col_):
+ return percent_bytes_;
+ case (bytes_col_):
+ return total_bytes_;
+ case (bandwidth_col_):
+ return bits_s_;
+ case (end_packets_col_):
+ return last_packets_;
+ case (end_bytes_col_):
+ return last_bytes_;
+ case (end_bandwidth_col_):
+ return end_bits_s_;
+ default:
+ break;
+ }
+ return QVariant();
+ }
+
bool operator< (const QTreeWidgetItem &other) const
{
const ProtocolHierarchyTreeWidgetItem &other_phtwi = dynamic_cast<const ProtocolHierarchyTreeWidgetItem&>(other);
@@ -252,6 +278,23 @@ ProtocolHierarchyDialog::ProtocolHierarchyDialog(QWidget &parent, CaptureFile &c
fa = new FilterAction(&ctx_menu_, FilterAction::ActionColorize);
ctx_menu_.addAction(fa);
+ ctx_menu_.addSeparator();
+ ctx_menu_.addAction(ui->actionCopyAsCsv);
+ ctx_menu_.addAction(ui->actionCopyAsYaml);
+
+ copy_button_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ApplyRole);
+
+ QMenu *copy_menu = new QMenu();
+ QAction *ca;
+ ca = copy_menu->addAction(tr("as CSV"));
+ ca->setToolTip(ui->actionCopyAsCsv->toolTip());
+ connect(ca, SIGNAL(triggered()), this, SLOT(on_actionCopyAsCsv_triggered()));
+ ca = copy_menu->addAction(tr("as YAML"));
+ ca->setToolTip(ui->actionCopyAsYaml->toolTip());
+ connect(ca, SIGNAL(triggered()), this, SLOT(on_actionCopyAsYaml_triggered()));
+ copy_button_->setMenu(copy_menu);
+
+
display_filter_ = cap_file_.capFile()->dfilter;
updateWidgets();
}
@@ -269,7 +312,9 @@ void ProtocolHierarchyDialog::showProtoHierMenu(QPoint pos)
submenu->setEnabled(enable);
}
foreach (QAction *action, ctx_menu_.actions()) {
- action->setEnabled(enable);
+ if (action != ui->actionCopyAsCsv && action != ui->actionCopyAsYaml) {
+ action->setEnabled(enable);
+ }
}
ctx_menu_.popup(ui->hierStatsTreeWidget->viewport()->mapToGlobal(pos));
@@ -314,6 +359,72 @@ void ProtocolHierarchyDialog::updateWidgets()
ui->hintLabel->setText(hint);
}
+QList<QVariant> ProtocolHierarchyDialog::protoHierRowData(QTreeWidgetItem *item) const
+{
+ QList<QVariant> row_data;
+
+ for (int col = 0; col < ui->hierStatsTreeWidget->columnCount(); col++) {
+ if (!item) {
+ row_data << ui->hierStatsTreeWidget->headerItem()->text(col);
+ } else {
+ ProtocolHierarchyTreeWidgetItem *phti = static_cast<ProtocolHierarchyTreeWidgetItem*>(item);
+ if (phti) {
+ row_data << phti->colData(col);
+ }
+ }
+ }
+ return row_data;
+}
+
+void ProtocolHierarchyDialog::on_actionCopyAsCsv_triggered()
+{
+ QString csv;
+ QTextStream stream(&csv, QIODevice::Text);
+ QTreeWidgetItemIterator iter(ui->hierStatsTreeWidget);
+ bool first = true;
+
+ while (*iter) {
+ QStringList separated_value;
+ QTreeWidgetItem *item = first ? NULL : (*iter);
+
+ foreach (QVariant v, protoHierRowData(item)) {
+ if (!v.isValid()) {
+ separated_value << "\"\"";
+ } else if ((int) v.type() == (int) QMetaType::QString) {
+ separated_value << QString("\"%1\"").arg(v.toString());
+ } else {
+ separated_value << v.toString();
+ }
+ }
+ stream << separated_value.join(",") << endl;
+
+ if (!first) iter++;
+ first = false;
+ }
+ wsApp->clipboard()->setText(stream.readAll());
+}
+
+void ProtocolHierarchyDialog::on_actionCopyAsYaml_triggered()
+{
+ QString yaml;
+ QTextStream stream(&yaml, QIODevice::Text);
+ QTreeWidgetItemIterator iter(ui->hierStatsTreeWidget);
+ bool first = true;
+
+ stream << "---" << endl;
+ while (*iter) {
+ QTreeWidgetItem *item = first ? NULL : (*iter);
+
+ stream << "-" << endl;
+ foreach (QVariant v, protoHierRowData(item)) {
+ stream << " - " << v.toString() << endl;
+ }
+ if (!first) iter++;
+ first = false;
+ }
+ wsApp->clipboard()->setText(stream.readAll());
+}
+
void ProtocolHierarchyDialog::on_buttonBox_helpRequested()
{
wsApp->helpTopicAction(HELP_STATS_PROTO_HIERARCHY_DIALOG);
diff --git a/ui/qt/protocol_hierarchy_dialog.h b/ui/qt/protocol_hierarchy_dialog.h
index e7d6e7aced..1c0fb47c59 100644
--- a/ui/qt/protocol_hierarchy_dialog.h
+++ b/ui/qt/protocol_hierarchy_dialog.h
@@ -27,6 +27,9 @@
#include <QMenu>
+class QPushButton;
+class QTreeWidgetItem;
+
namespace Ui {
class ProtocolHierarchyDialog;
}
@@ -63,10 +66,13 @@ signals:
private slots:
void showProtoHierMenu(QPoint pos);
void filterActionTriggered();
+ void on_actionCopyAsCsv_triggered();
+ void on_actionCopyAsYaml_triggered();
void on_buttonBox_helpRequested();
private:
Ui::ProtocolHierarchyDialog *ui;
+ QPushButton *copy_button_;
QMenu ctx_menu_;
PercentBarDelegate percent_bar_delegate_;
QString display_filter_;
@@ -74,6 +80,7 @@ private:
// Callback for g_node_children_foreach
static void addTreeNode(GNode *node, gpointer data);
void updateWidgets();
+ QList<QVariant> protoHierRowData(QTreeWidgetItem *item) const;
};
#endif // PROTOCOL_HIERARCHY_DIALOG_H
diff --git a/ui/qt/protocol_hierarchy_dialog.ui b/ui/qt/protocol_hierarchy_dialog.ui
index ea066ce916..2ae192f7ed 100644
--- a/ui/qt/protocol_hierarchy_dialog.ui
+++ b/ui/qt/protocol_hierarchy_dialog.ui
@@ -87,6 +87,22 @@
</widget>
</item>
</layout>
+ <action name="actionCopyAsCsv">
+ <property name="text">
+ <string>Copy as CSV</string>
+ </property>
+ <property name="toolTip">
+ <string>Copy stream list as CSV.</string>
+ </property>
+ </action>
+ <action name="actionCopyAsYaml">
+ <property name="text">
+ <string>Copy as YAML</string>
+ </property>
+ <property name="toolTip">
+ <string>Copy stream list as YAML.</string>
+ </property>
+ </action>
</widget>
<resources/>
<connections>