diff options
-rw-r--r-- | ui/qt/protocol_hierarchy_dialog.cpp | 131 | ||||
-rw-r--r-- | ui/qt/protocol_hierarchy_dialog.h | 7 | ||||
-rw-r--r-- | ui/qt/protocol_hierarchy_dialog.ui | 16 |
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> |