wireshark/ui/qt/traffic_table_dialog.cpp
Gerald Combs f80a720a88 WSUG and image updates.
Update the protocol hierarchy, conversation, and endpoint sections of
the User's Guide. When everything is an admonition nothing stands out.
Make a series of "NOTE"s plain old paragraphs. Scale the new
conversation and endpoint images to fit the page width. This looks funny
in my browser but I'm not sure about the best way to fix it.

Move image/compress-pngs to the tools directory. Use it to reduce the
size of the WSUG and WSDG images.

Fixup traffic table column names and window titles.

Change-Id: I674342ed901fc64563b384ee5e1f35413736cb19
Reviewed-on: https://code.wireshark.org/review/7122
Reviewed-by: Gerald Combs <gerald@wireshark.org>
2015-02-14 19:47:03 +00:00

352 lines
10 KiB
C++

/* traffic_table_dialog.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "traffic_table_dialog.h"
#include "ui_traffic_table_dialog.h"
#include <epan/addr_resolv.h>
#include <epan/prefs.h>
#include <epan/stat_tap_ui.h>
//#include <epan/dissectors/packet-tcp.h>
#include "ui/recent.h"
//#include "ui/tap-tcp-stream.h"
#include "wireshark_application.h"
#include <QCheckBox>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QDialogButtonBox>
#include <QList>
#include <QMap>
#include <QMessageBox>
#include <QPushButton>
#include <QTabWidget>
#include <QTreeWidget>
#include <QTextStream>
#include <QToolButton>
// To do:
// - Add "copy" items to the menu.
// Bugs:
// - Name resolution doesn't do anything if its preference is disabled.
// - Columns don't resize correctly.
// - Closing the capture file clears conversation data.
TrafficTableDialog::TrafficTableDialog(QWidget &parent, CaptureFile &cf, const char *filter, const QString &table_name) :
WiresharkDialog(parent, cf),
ui(new Ui::TrafficTableDialog),
cap_file_(cf),
file_closed_(false),
filter_(filter)
{
ui->setupUi(this);
ui->enabledTypesPushButton->setText(tr("%1 Types").arg(table_name));
setWindowSubtitle(QString("%1s").arg(table_name));
// XXX Use recent settings instead
resize(parent.width(), parent.height() * 3 / 4);
QMenu *copy_menu = new QMenu();
QAction *ca;
copy_bt_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
ca = copy_menu->addAction(tr("as CSV"));
ca->setToolTip(tr("Copy all values of this page to the clipboard in CSV (Comma Separated Values) format."));
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsCsv()));
ca = copy_menu->addAction(tr("as YAML"));
ca->setToolTip(tr("Copy all values of this page to the clipboard in the YAML data serialization format."));
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsYaml()));
copy_bt_->setMenu(copy_menu);
ui->enabledTypesPushButton->setMenu(&traffic_type_menu_);
ui->nameResolutionCheckBox->setChecked(gbl_resolv_flags.network_name);
ui->trafficTableTabWidget->setFocus();
connect(ui->trafficTableTabWidget, SIGNAL(currentChanged(int)),
this, SLOT(itemSelectionChanged()));
connect(&cap_file_, SIGNAL(captureFileClosing()), this, SLOT(captureFileClosing()));
}
TrafficTableDialog::~TrafficTableDialog()
{
delete ui;
}
const QList<int> TrafficTableDialog::defaultProtos() const
{
// Reasonable defaults?
return QList<int>() << proto_get_id_by_filter_name( "tcp" ) << proto_get_id_by_filter_name( "eth" )
<< proto_get_id_by_filter_name( "ip" ) << proto_get_id_by_filter_name( "ipv6" )
<< proto_get_id_by_filter_name( "udp" );
}
void TrafficTableDialog::fillTypeMenu(QList<int> &enabled_protos)
{
for (guint i = 0; i < conversation_table_get_num(); i++) {
int proto_id = get_conversation_proto_id(get_conversation_table_by_num(i));
if (proto_id < 0) {
continue;
}
QString title = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
QAction *endp_action = new QAction(title, this);
endp_action->setData(qVariantFromValue(proto_id));
endp_action->setCheckable(true);
endp_action->setChecked(enabled_protos.contains(proto_id));
connect(endp_action, SIGNAL(triggered()), this, SLOT(toggleTable()));
traffic_type_menu_.addAction(endp_action);
}
}
QDialogButtonBox *TrafficTableDialog::buttonBox() const
{
return ui->buttonBox;
}
QTabWidget *TrafficTableDialog::trafficTableTabWidget() const
{
return ui->trafficTableTabWidget;
}
QCheckBox *TrafficTableDialog::displayFilterCheckBox() const
{
return ui->displayFilterCheckBox;
}
QCheckBox *TrafficTableDialog::nameResolutionCheckBox() const
{
return ui->nameResolutionCheckBox;
}
QPushButton *TrafficTableDialog::enabledTypesPushButton() const
{
return ui->enabledTypesPushButton;
}
void TrafficTableDialog::on_nameResolutionCheckBox_toggled(bool checked)
{
Q_UNUSED(checked);
updateWidgets();
}
void TrafficTableDialog::on_displayFilterCheckBox_toggled(bool checked)
{
if (!cap_file_.isValid()) {
return;
}
QByteArray filter_utf8;
const char *filter = NULL;
if (checked) {
filter = cap_file_.capFile()->dfilter;
} else if (!filter_.isEmpty()) {
filter_utf8 = filter_.toUtf8();
filter = filter_utf8.constData();
}
for (int i = 0; i < ui->trafficTableTabWidget->count(); i++) {
TrafficTableTreeWidget *cur_tree = qobject_cast<TrafficTableTreeWidget *>(ui->trafficTableTabWidget->widget(i));
set_tap_dfilter(cur_tree->trafficTreeHash(), filter);
}
cap_file_.retapPackets();
}
void TrafficTableDialog::setTabText(QWidget *tree, const QString &text)
{
// Could use QObject::sender as well
int index = ui->trafficTableTabWidget->indexOf(tree);
if (index >= 0) {
ui->trafficTableTabWidget->setTabText(index, text);
}
}
void TrafficTableDialog::toggleTable()
{
QAction *ca = qobject_cast<QAction *>(QObject::sender());
if (!ca) {
return;
}
int proto_id = ca->data().value<int>();
register_ct_t* table = get_conversation_by_proto_id(proto_id);
bool new_table = addTrafficTable(table);
updateWidgets();
if (ca->isChecked()) {
ui->trafficTableTabWidget->setCurrentWidget(proto_id_to_tree_[proto_id]);
}
if (new_table) {
cap_file_.retapPackets();
}
}
void TrafficTableDialog::updateWidgets()
{
QWidget *cur_w = ui->trafficTableTabWidget->currentWidget();
ui->trafficTableTabWidget->setUpdatesEnabled(false);
ui->trafficTableTabWidget->clear();
foreach (QAction *ca, traffic_type_menu_.actions()) {
int proto_id = ca->data().value<int>();
if (proto_id_to_tree_.contains(proto_id) && ca->isChecked()) {
ui->trafficTableTabWidget->addTab(proto_id_to_tree_[proto_id],
proto_id_to_tree_[proto_id]->trafficTreeTitle());
proto_id_to_tree_[proto_id]->setNameResolutionEnabled(ui->nameResolutionCheckBox->isChecked());
}
}
ui->trafficTableTabWidget->setCurrentWidget(cur_w);
ui->trafficTableTabWidget->setUpdatesEnabled(true);
}
QList<QVariant> TrafficTableDialog::curTreeRowData(int row) const
{
TrafficTableTreeWidget *cur_tree = qobject_cast<TrafficTableTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
if (!cur_tree) {
return QList<QVariant>();
}
return cur_tree->rowData(row);
}
void TrafficTableDialog::copyAsCsv()
{
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
if (!cur_tree) {
return;
}
QString csv;
QTextStream stream(&csv, QIODevice::Text);
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
QStringList rdsl;
foreach (QVariant v, curTreeRowData(row)) {
if (!v.isValid()) {
rdsl << "\"\"";
} else if ((int) v.type() == (int) QMetaType::QString) {
rdsl << QString("\"%1\"").arg(v.toString());
} else {
rdsl << v.toString();
}
}
stream << rdsl.join(",") << endl;
}
wsApp->clipboard()->setText(stream.readAll());
}
void TrafficTableDialog::copyAsYaml()
{
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
if (!cur_tree) {
return;
}
QString yaml;
QTextStream stream(&yaml, QIODevice::Text);
stream << "---" << endl;
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
stream << "-" << endl;
foreach (QVariant v, curTreeRowData(row)) {
stream << " - " << v.toString() << endl;
}
}
wsApp->clipboard()->setText(stream.readAll());
}
TrafficTableTreeWidget::TrafficTableTreeWidget(QWidget *parent, register_ct_t *table) :
QTreeWidget(parent),
table_(table),
hash_(),
resolve_names_(false)
{
setRootIsDecorated(false);
sortByColumn(0, Qt::AscendingOrder);
connect(wsApp, SIGNAL(addressResolutionChanged()), this, SLOT(updateItems()));
}
TrafficTableTreeWidget::~TrafficTableTreeWidget()
{
remove_tap_listener(&hash_);
}
QList<QVariant> TrafficTableTreeWidget::rowData(int row) const
{
QList<QVariant> row_data;
if (row >= topLevelItemCount()) {
return row_data;
}
for (int col = 0; col < columnCount(); col++) {
if (isColumnHidden(col)) {
continue;
}
if (row < 0) {
row_data << headerItem()->text(col);
} else {
TrafficTableTreeWidgetItem *ti = static_cast<TrafficTableTreeWidgetItem *>(topLevelItem(row));
if (ti) {
row_data << ti->colData(col, resolve_names_);
}
}
}
return row_data;
}
void TrafficTableTreeWidget::setNameResolutionEnabled(bool enable)
{
if (resolve_names_ != enable) {
resolve_names_ = enable;
updateItems();
}
}
void TrafficTableTreeWidget::contextMenuEvent(QContextMenuEvent *event)
{
bool enable = currentItem() != NULL ? true : false;
foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) {
submenu->setEnabled(enable);
}
ctx_menu_.exec(event->globalPos());
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/