From a748e831438c52be7d40f1a28874d4f04ac2cda5 Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Wed, 4 Feb 2015 08:53:44 -0800 Subject: Qt: Add "Copy As..." to the Protocol Hierarchy stats. This implementation is slightly different compared to other dialogs since we have nested items. Tweak the bar highlight color look better on Windows while we're here. Change-Id: If0607c4624f304042fe3d6c8a941756b342e703d Reviewed-on: https://code.wireshark.org/review/6953 Petri-Dish: Gerald Combs Tested-by: Petri Dish Buildbot Reviewed-by: Gerald Combs --- ui/qt/protocol_hierarchy_dialog.cpp | 131 +++++++++++++++++++++++++++++++++--- ui/qt/protocol_hierarchy_dialog.h | 7 ++ ui/qt/protocol_hierarchy_dialog.ui | 16 +++++ 3 files changed, 144 insertions(+), 10 deletions(-) (limited to 'ui') 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 +#include #include -#include -#include +#include +#include +#include /* * @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 - 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(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 ProtocolHierarchyDialog::protoHierRowData(QTreeWidgetItem *item) const +{ + QList 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(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 +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 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 @@ + + + Copy as CSV + + + Copy stream list as CSV. + + + + + Copy as YAML + + + Copy stream list as YAML. + + -- cgit v1.2.3