1 /* export_dissection_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 #include "export_dissection_dialog.h"
12 #include "ui/alert_box.h"
13 #include "ui/help_url.h"
16 #include <epan/print.h>
17 #include <wsutil/filesystem.h>
19 #include <ui/qt/utils/qt_ui_utils.h>
22 #include <QDialogButtonBox>
23 #include <QGridLayout>
24 #include <QPushButton>
26 #include "main_application.h"
28 static const QStringList export_extensions
= QStringList()
38 ExportDissectionDialog::ExportDissectionDialog(QWidget
*parent
, capture_file
*cap_file
, export_type_e export_type
, QString selRange
):
39 WiresharkFileDialog(parent
),
40 export_type_(export_type
),
44 setWindowTitle(mainApp
->windowTitleString(tr("Export Packet Dissections")));
46 setDirectory(mainApp
->openDialogInitialDir());
48 setOption(QFileDialog::DontUseNativeDialog
, true);
49 QDialogButtonBox
*button_box
= findChild
<QDialogButtonBox
*>();
50 QGridLayout
*fd_grid
= qobject_cast
<QGridLayout
*>(layout());
51 QHBoxLayout
*h_box
= new QHBoxLayout();
52 QStringList name_filters
;
55 setAcceptMode(QFileDialog::AcceptSave
);
56 setLabelText(FileType
, tr("Export As:"));
58 // export_type_map_keys() sorts alphabetically. We don't want that.
60 << tr("Plain text (*.txt)")
61 << tr("Comma Separated Values - summary (*.csv)")
62 << tr("PSML - summary (*.psml, *.xml)")
63 << tr("PDML - details (*.pdml, *.xml)")
64 << tr("JSON (*.json)")
65 << tr("C Arrays - bytes (*.c, *.h)");
66 export_type_map_
[name_filters
[0]] = export_type_text
;
67 export_type_map_
[name_filters
[1]] = export_type_csv
;
68 export_type_map_
[name_filters
[2]] = export_type_psml
;
69 export_type_map_
[name_filters
[3]] = export_type_pdml
;
70 export_type_map_
[name_filters
[4]] = export_type_json
;
71 export_type_map_
[name_filters
[5]] = export_type_carrays
;
72 setNameFilters(name_filters
);
73 selectNameFilter(export_type_map_
.key(export_type
));
74 exportTypeChanged(export_type_map_
.key(export_type
));
76 last_row
= fd_grid
->rowCount();
77 fd_grid
->addItem(new QSpacerItem(1, 1), last_row
, 0);
78 fd_grid
->addLayout(h_box
, last_row
, 1);
80 print_args_
.file
= NULL
;
81 /* Init the export range */
82 packet_range_init(&print_args_
.range
, cap_file_
);
83 /* Default to displayed packets */
84 print_args_
.range
.process_filtered
= true;
86 packet_range_group_box_
.initRange(&print_args_
.range
, selRange
);
87 h_box
->addWidget(&packet_range_group_box_
);
89 h_box
->addWidget(&packet_format_group_box_
, 0, Qt::AlignTop
);
92 button_box
->addButton(QDialogButtonBox::Help
);
93 connect(button_box
, &QDialogButtonBox::helpRequested
, this, &ExportDissectionDialog::on_buttonBox_helpRequested
);
95 save_bt_
= button_box
->button(QDialogButtonBox::Save
);
99 connect(&packet_range_group_box_
, &PacketRangeGroupBox::validityChanged
,
100 this, &ExportDissectionDialog::checkValidity
);
101 connect(&packet_format_group_box_
, &PacketFormatGroupBox::formatChanged
,
102 this, &ExportDissectionDialog::checkValidity
);
103 save_bt_
->installEventFilter(this);
105 connect(this, &ExportDissectionDialog::filterSelected
, this, &ExportDissectionDialog::exportTypeChanged
);
107 // Grow the dialog to account for the extra widgets.
108 resize(width(), height() + (packet_range_group_box_
.height() * 2 / 3));
110 connect(this, &ExportDissectionDialog::filesSelected
, this, &ExportDissectionDialog::dialogAccepted
);
113 ExportDissectionDialog::~ExportDissectionDialog()
115 g_free(print_args_
.file
);
116 packet_range_cleanup(&print_args_
.range
);
119 void ExportDissectionDialog::show()
122 WiresharkFileDialog::show();
126 void ExportDissectionDialog::dialogAccepted(const QStringList
&selected
)
128 if (selected
.length() > 0) {
129 /* writing might take a while, so hide ourselves so the user
130 * can't click on anything here (this dialog will be closed
131 * and deleted once this function is done), but can access
132 * the ProgressDialog in the main window to cancel the export.
135 cf_print_status_t status
;
136 QString file_name
= QDir::toNativeSeparators(selected
[0]);
138 /* Fill in our print (and export) args */
140 print_args_
.file
= qstring_strdup(file_name
);
141 print_args_
.format
= PR_FMT_TEXT
;
142 print_args_
.to_file
= true;
143 print_args_
.cmd
= NULL
;
144 print_args_
.print_summary
= true;
145 print_args_
.print_col_headings
= true;
146 print_args_
.print_dissections
= print_dissections_as_displayed
;
147 print_args_
.print_hex
= false;
148 print_args_
.print_formfeed
= false;
150 switch (export_type_
) {
151 case export_type_text
: /* Text */
152 print_args_
.print_summary
= packet_format_group_box_
.summaryEnabled();
153 print_args_
.print_col_headings
= packet_format_group_box_
.includeColumnHeadingsEnabled();
154 print_args_
.print_dissections
= print_dissections_none
;
155 if (packet_format_group_box_
.detailsEnabled()) {
156 if (packet_format_group_box_
.allCollapsedEnabled())
157 print_args_
.print_dissections
= print_dissections_collapsed
;
158 else if (packet_format_group_box_
.asDisplayedEnabled())
159 print_args_
.print_dissections
= print_dissections_as_displayed
;
160 else if (packet_format_group_box_
.allExpandedEnabled())
161 print_args_
.print_dissections
= print_dissections_expanded
;
163 print_args_
.print_hex
= packet_format_group_box_
.bytesEnabled();
164 print_args_
.hexdump_options
= packet_format_group_box_
.getHexdumpOptions();
165 print_args_
.stream
= print_stream_text_new(true, print_args_
.file
);
166 if (print_args_
.stream
== NULL
) {
167 open_failure_alert_box(print_args_
.file
, errno
, true);
170 status
= cf_print_packets(cap_file_
, &print_args_
, true);
172 case export_type_csv
: /* CSV */
173 status
= cf_write_csv_packets(cap_file_
, &print_args_
);
175 case export_type_carrays
: /* C Arrays */
176 status
= cf_write_carrays_packets(cap_file_
, &print_args_
);
178 case export_type_psml
: /* PSML */
179 status
= cf_write_psml_packets(cap_file_
, &print_args_
);
181 case export_type_pdml
: /* PDML */
182 status
= cf_write_pdml_packets(cap_file_
, &print_args_
);
184 case export_type_json
: /* JSON */
185 status
= cf_write_json_packets(cap_file_
, &print_args_
);
194 case CF_PRINT_OPEN_ERROR
:
195 open_failure_alert_box(print_args_
.file
, errno
, true);
197 case CF_PRINT_WRITE_ERROR
:
198 write_failure_alert_box(print_args_
.file
, errno
);
203 /* Save the directory name for future file dialogs. */
204 dirname
= get_dirname(print_args_
.file
); /* Overwrites file_name data */
205 set_last_open_dir(dirname
);
209 void ExportDissectionDialog::exportTypeChanged(QString name_filter
)
211 export_type_
= export_type_map_
.value(name_filter
);
212 if (export_type_
== export_type_text
) {
213 packet_format_group_box_
.setEnabled(true);
214 print_args_
.format
= PR_FMT_TEXT
;
216 packet_format_group_box_
.setEnabled(false);
220 setDefaultSuffix(export_extensions
[export_type_
]);
223 bool ExportDissectionDialog::isValid()
227 if (!packet_range_group_box_
.isValid()) valid
= false;
229 if (export_type_
== export_type_text
) {
230 if (! packet_format_group_box_
.summaryEnabled() &&
231 ! packet_format_group_box_
.detailsEnabled() &&
232 ! packet_format_group_box_
.bytesEnabled())
241 void ExportDissectionDialog::checkValidity()
243 if (!save_bt_
) return;
245 save_bt_
->setEnabled(isValid());
248 void ExportDissectionDialog::on_buttonBox_helpRequested()
250 mainApp
->helpTopicAction(HELP_EXPORT_FILE_DIALOG
);
253 bool ExportDissectionDialog::eventFilter(QObject
*obj
, QEvent
*event
)
255 // The QFileDialogPrivate will enable the Ok (Open/Save) button when
256 // anything is typed or selected. We can't catch that beforehand, so
257 // watch for the enable status change and re-disable it if the
258 // group boxes are invalid.
259 // We could do extra work (here and elsewhere) not to disable the button
260 // if what's selected in the dialog is a directory, but even with save_bt_
261 // disabled clicking on the directory still opens it.
262 if (event
->type() == QEvent::EnabledChange
) {
263 QPushButton
*button
= qobject_cast
<QPushButton
*>(obj
);
264 if (button
&& button
== save_bt_
) {
265 // The button is already changed by the time we get this event.
266 if (button
->isEnabled() && !isValid()) {
267 button
->setEnabled(false);
273 return QObject::eventFilter(obj
, event
);