1 /* stats_tree_dialog.cpp
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "stats_tree_dialog.h"
25 #include "ui_stats_tree_dialog.h"
29 #include "epan/stats_tree_priv.h"
30 #include "wsutil/file_util.h"
31 #include "ui/last_open_dir.h"
33 #include "wireshark_application.h"
36 #include <QMessageBox>
37 #include <QTreeWidget>
38 #include <QTreeWidgetItemIterator>
39 #include <QFileDialog>
41 // The GTK+ counterpart uses tap_param_dlg, which we don't use. If we
42 // need tap parameters we should probably create a TapParameterDialog
43 // class based on QDialog and subclass it here.
50 const int item_col_ = 0;
52 Q_DECLARE_METATYPE(stat_node *);
54 class StatsTreeWidgetItem : public QTreeWidgetItem
57 StatsTreeWidgetItem(int type = Type) : QTreeWidgetItem (type) {}
58 bool operator< (const QTreeWidgetItem &other) const
60 stat_node *thisnode = data(item_col_, Qt::UserRole).value<stat_node *>();
61 stat_node *othernode = other.data(item_col_, Qt::UserRole).value<stat_node *>();
62 Qt::SortOrder order = treeWidget()->header()->sortIndicatorOrder();
65 result = stats_tree_sort_compare(thisnode, othernode, treeWidget()->sortColumn(),
66 order==Qt::DescendingOrder);
67 if (order==Qt::DescendingOrder) {
74 StatsTreeDialog::StatsTreeDialog(QWidget *parent, capture_file *cf, const char *cfg_abbr) :
76 ui(new Ui::StatsTreeDialog),
82 st_cfg_ = stats_tree_get_cfg_by_abbr(cfg_abbr);
85 QMessageBox::critical(this, tr("Configuration not found"),
86 tr("Unable to find configuration for %1.").arg(cfg_abbr));
87 QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
90 ui->statsTreeWidget->addAction(ui->actionCopyToClipboard);
91 ui->statsTreeWidget->addAction(ui->actionSaveAs);
92 ui->statsTreeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
95 button = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
96 connect(button, SIGNAL(clicked()), this, SLOT(on_actionCopyToClipboard_triggered()));
98 button = ui->buttonBox->addButton(tr("Save as..."), QDialogButtonBox::ActionRole);
99 connect(button, SIGNAL(clicked()), this, SLOT(on_actionSaveAs_triggered()));
104 StatsTreeDialog::~StatsTreeDialog()
107 stats_tree_free(st_);
112 void StatsTreeDialog::setCaptureFile(capture_file *cf)
114 if (!cf) { // We only want to know when the file closes.
116 ui->displayFilterLineEdit->setEnabled(false);
117 ui->applyFilterButton->setEnabled(false);
121 void StatsTreeDialog::fillTree()
123 GString *error_string;
124 if (!st_cfg_) return;
126 gchar* display_name_temp = stats_tree_get_displayname(st_cfg_->name);
127 QString display_name(display_name_temp);
128 g_free(display_name_temp);
130 setWindowTitle(display_name + tr(" Stats Tree"));
132 if (!cap_file_) return;
134 if (st_cfg_->in_use) {
135 QMessageBox::warning(this, tr("%1 already open").arg(display_name),
136 tr("Each type of tree can only be generated one at at time."));
140 st_cfg_->in_use = TRUE;
141 st_cfg_->pr = &cfg_pr_;
142 cfg_pr_.st_dlg = this;
145 stats_tree_free(st_);
147 st_ = stats_tree_new(st_cfg_, NULL, ui->displayFilterLineEdit->text().toUtf8().constData());
149 // Add number of columns for this stats_tree
150 QStringList headerLabels;
151 for (int count = 0; count<st_->num_columns; count++) {
152 headerLabels.push_back(stats_tree_get_column_name(count));
154 ui->statsTreeWidget->setColumnCount(headerLabels.count());
155 ui->statsTreeWidget->setHeaderLabels(headerLabels);
156 resize(st_->num_columns*80+80, height());
157 for (int count = 0; count<st_->num_columns; count++) {
158 headerLabels.push_back(stats_tree_get_column_name(count));
160 ui->statsTreeWidget->setSortingEnabled(false);
162 error_string = register_tap_listener(st_cfg_->tapname,
170 QMessageBox::critical(this, tr("%1 failed to attach to tap").arg(display_name),
172 g_string_free(error_string, TRUE);
176 cf_retap_packets(cap_file_);
179 ui->statsTreeWidget->setSortingEnabled(true);
180 remove_tap_listener(st_);
182 st_cfg_->in_use = FALSE;
186 void StatsTreeDialog::resetTap(void *st_ptr)
188 stats_tree *st = (stats_tree *) st_ptr;
189 if (!st || !st->cfg || !st->cfg->pr || !st->cfg->pr->st_dlg) return;
191 st->cfg->pr->st_dlg->ui->statsTreeWidget->clear();
195 // Adds a node to the QTreeWidget
196 // Note: We're passing QTreeWidgetItem pointers as st_node_pres pointers
197 void StatsTreeDialog::setupNode(stat_node* node)
199 if (!node || !node->st || !node->st->cfg || !node->st->cfg->pr
200 || !node->st->cfg->pr->st_dlg) return;
201 StatsTreeDialog *st_dlg = node->st->cfg->pr->st_dlg;
203 QTreeWidgetItem *ti = new StatsTreeWidgetItem(), *parent = NULL;
205 ti->setText(item_col_, node->name);
206 ti->setData(item_col_, Qt::UserRole, qVariantFromValue(node));
207 node->pr = (st_node_pres *) ti;
208 if (node->parent && node->parent->pr) {
209 parent = (QTreeWidgetItem *) node->parent->pr;
210 parent->setExpanded(true);
213 parent->addChild(ti);
215 st_dlg->ui->statsTreeWidget->addTopLevelItem(ti);
217 st_dlg->ui->statsTreeWidget->resizeColumnToContents(item_col_);
220 void StatsTreeDialog::drawTreeItems(void *st_ptr)
222 stats_tree *st = (stats_tree *) st_ptr;
223 if (!st || !st->cfg || !st->cfg->pr || !st->cfg->pr->st_dlg) return;
224 StatsTreeDialog *st_dlg = st->cfg->pr->st_dlg;
225 QTreeWidgetItemIterator iter(st_dlg->ui->statsTreeWidget);
228 stat_node *node = (*iter)->data(item_col_, Qt::UserRole).value<stat_node *>();
230 gchar **valstrs = stats_tree_get_values_from_node(node);
231 for (int count = 0; count<st->num_columns; count++) {
232 (*iter)->setText(count,valstrs[count]);
233 g_free(valstrs[count]);
235 if (node->parent==(&st->root)) {
236 (*iter)->setExpanded(!(node->st_flags&ST_FLG_DEF_NOEXPAND));
242 for (int count = 0; count<st->num_columns; count++) {
243 st_dlg->ui->statsTreeWidget->resizeColumnToContents(count);
247 void StatsTreeDialog::on_applyFilterButton_clicked()
252 void StatsTreeDialog::on_actionCopyToClipboard_triggered()
254 GString* s= stats_tree_format_as_str(st_ ,ST_FORMAT_PLAIN, ui->statsTreeWidget->sortColumn(),
255 ui->statsTreeWidget->header()->sortIndicatorOrder()==Qt::DescendingOrder);
256 wsApp->clipboard()->setText(s->str);
257 g_string_free(s,TRUE);
260 void StatsTreeDialog::on_actionSaveAs_triggered()
262 QString selectedFilter;
263 st_format_type file_type;
264 const char *file_ext;
270 QFileDialog SaveAsDialog(this, tr("Wireshark: Save stats tree as ..."), get_last_open_dir());
271 SaveAsDialog.setNameFilter(tr("Plain text file (*.txt);;"
272 "Comma separated values (*.csv);;"
273 "XML document (*.xml);;"
274 "YAML document (*.yaml)"));
275 SaveAsDialog.selectNameFilter(tr("Plain text file (*.txt)"));
276 SaveAsDialog.setAcceptMode(QFileDialog::AcceptSave);
277 if (!SaveAsDialog.exec()) {
280 selectedFilter= SaveAsDialog.selectedNameFilter();
281 if (selectedFilter.contains("*.yaml", Qt::CaseInsensitive)) {
282 file_type= ST_FORMAT_YAML;
285 else if (selectedFilter.contains("*.xml", Qt::CaseInsensitive)) {
286 file_type= ST_FORMAT_XML;
289 else if (selectedFilter.contains("*.csv", Qt::CaseInsensitive)) {
290 file_type= ST_FORMAT_CSV;
294 file_type= ST_FORMAT_PLAIN;
298 // Get selected filename and add extension of necessary
299 QString file_name = SaveAsDialog.selectedFiles()[0];
300 if (!file_name.endsWith(file_ext, Qt::CaseInsensitive)) {
301 file_name.append(file_ext);
304 // produce output in selected format using current sort information
305 str_tree=stats_tree_format_as_str(st_ ,file_type, ui->statsTreeWidget->sortColumn(),
306 ui->statsTreeWidget->header()->sortIndicatorOrder()==Qt::DescendingOrder);
308 // actually save the file
309 f= ws_fopen (file_name.toUtf8().constData(),"w");
312 if (fputs(str_tree->str, f)!=EOF) {
319 QMessageBox::warning(this, tr("Error saving file %1").arg(file_name),
320 g_strerror (last_errno));
323 g_string_free(str_tree, TRUE);
328 register_tap_listener_stats_tree_stat(void)
331 stats_tree_presentation(NULL,
332 StatsTreeDialog::setupNode,
350 * indent-tabs-mode: nil
353 * ex: set shiftwidth=4 tabstop=8 expandtab:
354 * :indentSize=4:tabSize=8:noTabs=true: