1 /* export_object_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_object_dialog.h"
11 #include <ui_export_object_dialog.h>
13 #include <ui/alert_box.h>
14 #include <wsutil/utf8_entities.h>
16 #include "main_application.h"
17 #include "ui/qt/widgets/wireshark_file_dialog.h"
18 #include <ui/qt/widgets/export_objects_view.h>
19 #include <ui/qt/models/export_objects_model.h>
20 #include <ui/qt/utils/qt_ui_utils.h>
22 #include <QDialogButtonBox>
23 #include <QMessageBox>
24 #include <QMimeDatabase>
25 #include <QPushButton>
30 #include <QDesktopServices>
32 ExportObjectDialog::ExportObjectDialog(QWidget
&parent
, CaptureFile
&cf
, register_eo_t
* eo
) :
33 WiresharkDialog(parent
, cf
),
34 eo_ui_(new Ui::ExportObjectDialog
),
40 QPushButton
*close_bt
;
42 eo_ui_
->setupUi(this);
43 setAttribute(Qt::WA_DeleteOnClose
, true);
45 proxyModel_
.setSourceModel(&model_
);
46 eo_ui_
->objectTree
->setModel(&proxyModel_
);
48 proxyModel_
.setFilterFixedString("");
49 proxyModel_
.setFilterCaseSensitivity(Qt::CaseInsensitive
);
50 proxyModel_
.setFilterKeyColumn(-1);
53 eo_ui_
->progressLabel
->setAttribute(Qt::WA_MacSmallSize
, true);
54 eo_ui_
->progressBar
->setAttribute(Qt::WA_MacSmallSize
, true);
57 connect(&model_
, &ExportObjectModel::rowsInserted
,
58 this, &ExportObjectDialog::modelDataChanged
);
59 connect(&model_
, &ExportObjectModel::modelReset
, this, &ExportObjectDialog::modelRowsReset
);
60 connect(eo_ui_
->filterLine
, &QLineEdit::textChanged
, &proxyModel_
, &ExportObjectProxyModel::setTextFilterString
);
61 connect(eo_ui_
->objectTree
, &ExportObjectsTreeView::currentIndexChanged
, this, &ExportObjectDialog::currentHasChanged
);
63 save_bt_
= eo_ui_
->buttonBox
->button(QDialogButtonBox::Save
);
64 save_all_bt_
= eo_ui_
->buttonBox
->button(QDialogButtonBox::SaveAll
);
65 close_bt
= eo_ui_
->buttonBox
->button(QDialogButtonBox::Close
);
66 if (eo_ui_
->buttonBox
->button(QDialogButtonBox::Open
))
68 QPushButton
* open
= eo_ui_
->buttonBox
->button(QDialogButtonBox::Open
);
69 open
->setText(tr("Preview"));
70 open
->setEnabled(false);
73 contentTypes
<< tr("All Content-Types");
74 eo_ui_
->cmbContentType
->addItems(contentTypes
);
76 setWindowTitle(mainApp
->windowTitleString(QStringList() << tr("Export") << tr("%1 object list").arg(proto_get_protocol_short_name(find_protocol_by_id(get_eo_proto_id(eo
))))));
78 if (save_bt_
) save_bt_
->setEnabled(false);
79 if (save_all_bt_
) save_all_bt_
->setEnabled(false);
80 if (close_bt
) close_bt
->setDefault(true);
82 connect(&cap_file_
, &CaptureFile::captureEvent
,
83 this, &ExportObjectDialog::captureEvent
);
86 ExportObjectDialog::~ExportObjectDialog()
93 void ExportObjectDialog::currentHasChanged(QModelIndex current
)
95 if (current
.isValid())
97 QModelIndex sibl
= current
.sibling(current
.row(), ExportObjectModel::colPacket
);
98 if (eo_ui_
->buttonBox
->button(QDialogButtonBox::Open
))
100 QString mime_type
= sibl
.sibling(current
.row(), ExportObjectModel::colContent
).data().toString();
101 eo_ui_
->buttonBox
->button(QDialogButtonBox::Open
)->setEnabled(mimeTypeIsPreviewable(mime_type
));
103 mainApp
->gotoFrame(sibl
.data().toInt());
107 bool ExportObjectDialog::mimeTypeIsPreviewable(QString mime_type
)
109 // XXX This excludes everything except HTTP. Maybe that's a good thing?
110 // Take care when adding to this, e.g. text/html or image/svg might contain JavaScript.
111 QStringList previewable_mime_types
= QStringList()
113 << "image/gif" << "image/jpeg" << "image/png";
115 if (previewable_mime_types
.contains(mime_type
)) {
121 void ExportObjectDialog::modelDataChanged(const QModelIndex
&, int from
, int to
)
123 bool contentTypes_changed
= false;
124 bool enabled
= (model_
.rowCount() > 0);
125 if (save_bt_
) save_bt_
->setEnabled(enabled
);
126 if (save_all_bt_
) save_all_bt_
->setEnabled(enabled
);
128 for (int row
= from
; row
<= to
; row
++)
130 QModelIndex idx
= model_
.index(row
, ExportObjectModel::colContent
);
133 QString dataType
= idx
.data().toString();
134 if (dataType
.length() > 0 && ! contentTypes
.contains(dataType
))
136 contentTypes
<< dataType
;
137 contentTypes_changed
= true;
141 if (contentTypes_changed
) {
142 contentTypes
.sort(Qt::CaseInsensitive
);
143 QString selType
= eo_ui_
->cmbContentType
->currentText();
144 eo_ui_
->cmbContentType
->clear();
145 eo_ui_
->cmbContentType
->addItem(tr("All Content-Types"));
146 eo_ui_
->cmbContentType
->addItems(contentTypes
);
147 if (contentTypes
.contains(selType
) )
148 eo_ui_
->cmbContentType
->setCurrentText(selType
);
152 void ExportObjectDialog::modelRowsReset()
154 contentTypes
.clear();
155 eo_ui_
->cmbContentType
->clear();
156 eo_ui_
->cmbContentType
->addItem(tr("All Content-Types"));
158 if (save_bt_
) save_bt_
->setEnabled(false);
159 if (save_all_bt_
) save_all_bt_
->setEnabled(false);
162 void ExportObjectDialog::show()
164 /* Data will be gathered via a tap callback */
165 if (!registerTapListener(model_
.getTapListenerName(), model_
.getTapData(), NULL
, 0,
166 ExportObjectModel::resetTap
,
167 model_
.getTapPacketFunc(),
173 cap_file_
.retapPackets();
174 eo_ui_
->progressFrame
->hide();
175 for (int i
= 0; i
< eo_ui_
->objectTree
->model()->columnCount(); i
++)
176 eo_ui_
->objectTree
->resizeColumnToContents(i
);
178 eo_ui_
->objectTree
->sortByColumn(ExportObjectModel::colPacket
, Qt::AscendingOrder
);
181 void ExportObjectDialog::keyPressEvent(QKeyEvent
*evt
)
183 if(evt
->key() == Qt::Key_Enter
|| evt
->key() == Qt::Key_Return
)
185 QDialog::keyPressEvent(evt
);
188 void ExportObjectDialog::accept()
190 // Don't close the dialog.
193 void ExportObjectDialog::captureEvent(CaptureEvent e
)
195 if ((e
.captureContext() == CaptureEvent::File
) &&
196 (e
.eventType() == CaptureEvent::Closing
))
202 void ExportObjectDialog::on_buttonBox_helpRequested()
204 mainApp
->helpTopicAction(HELP_EXPORT_OBJECT_LIST
);
207 void ExportObjectDialog::on_buttonBox_clicked(QAbstractButton
*button
)
209 switch (eo_ui_
->buttonBox
->standardButton(button
)) {
210 case QDialogButtonBox::Save
:
213 case QDialogButtonBox::SaveAll
:
216 case QDialogButtonBox::Open
:
219 saveCurrentEntry(&temp
);
221 if (temp
.length() > 0) {
222 QMimeDatabase mime_db
;
223 QMimeType mime_type
= mime_db
.mimeTypeForFile(temp
, QMimeDatabase::MatchContent
);
224 if (mimeTypeIsPreviewable(mime_type
.name())) {
225 QDesktopServices::openUrl(QUrl(QStringLiteral("file:///").append(temp
), QUrl::TolerantMode
));
227 desktop_show_in_folder(temp
);
233 default: // Help, Cancel
238 void ExportObjectDialog::on_cmbContentType_currentIndexChanged(int index
)
240 QString filterString
= index
<= 0 ? "" : eo_ui_
->cmbContentType
->currentText();
241 proxyModel_
.setContentFilterString(filterString
);
245 void ExportObjectDialog::saveCurrentEntry(QString
*tempFile
)
247 QDir
path(mainApp
->openDialogInitialDir());
249 QModelIndex proxyIndex
= eo_ui_
->objectTree
->currentIndex();
250 if (!proxyIndex
.isValid())
253 QModelIndex current
= proxyModel_
.mapToSource(proxyIndex
);
254 if (!current
.isValid())
257 QString entry_filename
= current
.sibling(current
.row(), ExportObjectModel::colFilename
).data().toString();
258 if (entry_filename
.isEmpty())
264 GString
*safe_filename
= eo_massage_str(entry_filename
.toUtf8().constData(), EXPORT_OBJECT_MAXFILELEN
, 0);
265 file_name
= WiresharkFileDialog::getSaveFileName(this, mainApp
->windowTitleString(tr("Save Object As…")),
267 g_string_free(safe_filename
, TRUE
);
269 QString path
= QDir::tempPath().append("/").append(entry_filename
);
270 /* This means, the system must remove the file! */
272 if (QFileInfo::exists(path
))
277 model_
.saveEntry(current
, file_name
);
280 void ExportObjectDialog::saveAllEntries()
282 QDir
save_in_dir(mainApp
->openDialogInitialDir());
283 QString save_in_path
;
286 // We want the user to be able to specify a directory in which
287 // to drop files for all the objects, not a file name.
289 // XXX - what we *really* want is something that asks the user
290 // for an existing directory *but* lets them create a new
291 // directory in the process. That's what we get on macOS,
292 // as the native dialog is used, and it supports that; does
293 // that also work on Windows and with Qt's own dialog?
295 save_in_path
= WiresharkFileDialog::getExistingDirectory(this, mainApp
->windowTitleString(tr("Save All Objects In…")),
296 save_in_dir
.canonicalPath(),
297 QFileDialog::ShowDirsOnly
);
299 if (save_in_path
.length() < 1)
302 model_
.saveAllEntries(save_in_path
);