aboutsummaryrefslogtreecommitdiffstats
path: root/ui/qt/capture_file_dialog.cpp
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2018-04-28 13:15:36 +0200
committerAnders Broman <a.broman58@gmail.com>2018-05-01 10:24:07 +0000
commit552ef8b1f4bc5ced263c82253ed21793ca8e5d5e (patch)
treeab6e44f9cae1f299266e2000bd7ff9d5e5fc1659 /ui/qt/capture_file_dialog.cpp
parent6e4caf3d90862c36c451f48abe7533fa92ecf58b (diff)
Qt: improve extension selection in Save As dialog
The default Qt behavior for extension adjustment is quite bad. When the file type filter is changed, the extension always becomes "gz" because "pcap.gz" happens to be the first extension in the list. It also did not check that the last suffix is actually a valid extension (e.g. "capture.2018.01" became "capture.2018.gz"). Improvements: - Respect the "compression" checkbox when adjusting the filename. - Replace the extension only if it is a known one, append otherwise. - Use a better default extension (from "wtap_default_file_extension"). Affects only macOS and Linux since Windows has its own native dialog. See also https://bugreports.qt.io/browse/QTBUG-67993 Bug: 14600 Change-Id: I8cd0788f2abac0c6d7e29490b1ebb381f5a926d0 Reviewed-on: https://code.wireshark.org/review/27186 Reviewed-by: Peter Wu <peter@lekensteyn.nl> Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'ui/qt/capture_file_dialog.cpp')
-rw-r--r--ui/qt/capture_file_dialog.cpp107
1 files changed, 84 insertions, 23 deletions
diff --git a/ui/qt/capture_file_dialog.cpp b/ui/qt/capture_file_dialog.cpp
index 2df11d46ce..90719d6a3e 100644
--- a/ui/qt/capture_file_dialog.cpp
+++ b/ui/qt/capture_file_dialog.cpp
@@ -303,7 +303,7 @@ int CaptureFileDialog::mergeType() {
return merge_type_;
}
-#else // not Q_OS_WINDOWS
+#else // ! Q_OS_WIN
// Not Windows
// We use the Qt dialogs here
QString CaptureFileDialog::fileExtensionType(int et, bool extension_globs)
@@ -342,18 +342,14 @@ QString CaptureFileDialog::fileExtensionType(int et, bool extension_globs)
.arg(all_wildcards.join(" "));
}
-QString CaptureFileDialog::fileType(int ft, bool extension_globs)
+// Returns " (...)", containing the suffix list suitable for setNameFilters.
+// All extensions ("pcap", "pcap.gz", etc.) are also returned in "suffixes".
+QString CaptureFileDialog::fileType(int ft, QStringList &suffixes)
{
QString filter;
GSList *extensions_list;
- filter = wtap_file_type_subtype_string(ft);
-
- if (!extension_globs) {
- return filter;
- }
-
- filter += " (";
+ filter = " (";
extensions_list = wtap_get_file_extensions_list(ft, TRUE);
if (extensions_list == NULL) {
@@ -364,20 +360,22 @@ QString CaptureFileDialog::fileType(int ft, bool extension_globs)
compressed file extensions. */
filter += ALL_FILES_WILDCARD;
} else {
- GSList *extension;
+ // HACK: at least for Qt 5.10 and before, if the first extension is
+ // empty ("."), it will prevent the default (broken) extension
+ // replacement from being applied in the non-native Save file dialog.
+ filter += '.';
+
/* Construct the list of patterns. */
- for (extension = extensions_list; extension != NULL;
+ for (GSList *extension = extensions_list; extension != NULL;
extension = g_slist_next(extension)) {
- if (!filter.endsWith('('))
- filter += ' ';
- filter += "*.";
- filter += (char *)extension->data;
+ QString suffix((char *)extension->data);
+ filter += " *." + suffix;;
+ suffixes << suffix;
}
wtap_free_extensions_list(extensions_list);
}
filter += ')';
return filter;
- /* XXX - does QStringList's destructor destroy the strings in the list? */
}
QStringList CaptureFileDialog::buildFileOpenTypeList() {
@@ -434,6 +432,68 @@ QStringList CaptureFileDialog::buildFileOpenTypeList() {
return filters;
}
+// Replaces or appends an extension based on the current file filter.
+void CaptureFileDialog::fixFilenameExtension()
+{
+ QFileInfo fi(selectedFiles()[0]);
+ QString filename = fi.fileName();
+ if (fi.isDir() || filename.isEmpty()) {
+ // no file selected, or a directory was selected. Ignore.
+ return;
+ }
+
+ QString old_suffix;
+ QString new_suffix(wtap_default_file_extension(selectedFileType()));
+ QStringList valid_extensions = type_suffixes_.value(selectedNameFilter());
+ // Find suffixes such as "pcap" or "pcap.gz" if any
+ if (!fi.suffix().isEmpty()) {
+ QStringList current_suffixes(fi.suffix());
+ int pos = filename.lastIndexOf('.', -2 - current_suffixes.at(0).size());
+ if (pos > 0) {
+ current_suffixes.prepend(filename.right(filename.size() - (pos + 1)));
+ }
+
+ // If the current suffix is valid for the current file type, try to
+ // preserve it. Otherwise use the default file extension (if available).
+ foreach (const QString &current_suffix, current_suffixes) {
+ if (valid_extensions.contains(current_suffix)) {
+ old_suffix = current_suffix;
+ new_suffix = current_suffix;
+ break;
+ }
+ }
+ if (old_suffix.isEmpty()) {
+ foreach (const QString &current_suffix, current_suffixes) {
+ foreach (const QStringList &suffixes, type_suffixes_.values()) {
+ if (suffixes.contains(current_suffix)) {
+ old_suffix = current_suffix;
+ break;
+ }
+ }
+ if (!old_suffix.isEmpty()) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Fixup the new suffix based on compression availability.
+ if (!isCompressed() && new_suffix.endsWith(".gz")) {
+ new_suffix.chop(3);
+ } else if (isCompressed() && valid_extensions.contains(new_suffix + ".gz")) {
+ new_suffix += ".gz";
+ }
+
+ if (!new_suffix.isEmpty() && old_suffix != new_suffix) {
+ filename.chop(old_suffix.size());
+ if (old_suffix.isEmpty()) {
+ filename += '.';
+ }
+ filename += new_suffix;
+ selectFile(filename);
+ }
+}
+
void CaptureFileDialog::addPreview(QVBoxLayout &v_box) {
QGridLayout *preview_grid = new QGridLayout();
QLabel *lbl;
@@ -516,6 +576,7 @@ void CaptureFileDialog::addGzipControls(QVBoxLayout &v_box) {
compress_.setChecked(false);
}
v_box.addWidget(&compress_, 0, Qt::AlignTop);
+ connect(&compress_, &QCheckBox::stateChanged, this, &CaptureFileDialog::fixFilenameExtension);
}
@@ -587,6 +648,7 @@ check_savability_t CaptureFileDialog::saveAs(QString &file_name, bool must_suppo
if (!file_name.isEmpty()) {
selectFile(file_name);
}
+ connect(this, &QFileDialog::filterSelected, this, &CaptureFileDialog::fixFilenameExtension);
if (QFileDialog::exec() && selectedFiles().length() > 0) {
file_name = selectedFiles()[0];
@@ -622,6 +684,7 @@ check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name,
if (!file_name.isEmpty()) {
selectFile(file_name);
}
+ connect(this, &QFileDialog::filterSelected, this, &CaptureFileDialog::fixFilenameExtension);
if (QFileDialog::exec() && selectedFiles().length() > 0) {
file_name = selectedFiles()[0];
@@ -663,6 +726,7 @@ QStringList CaptureFileDialog::buildFileSaveAsTypeList(bool must_support_all_com
guint i;
type_hash_.clear();
+ type_suffixes_.clear();
/* What types of comments do we have to support? */
if (must_support_all_comments)
@@ -676,8 +740,6 @@ QStringList CaptureFileDialog::buildFileSaveAsTypeList(bool must_support_all_com
required_comment_types);
if (savable_file_types_subtypes != NULL) {
- QString file_type;
- QString hash_file_type;
int ft;
/* OK, we have at least one file type we can save this file as.
(If we didn't, we shouldn't have gotten here in the first
@@ -686,10 +748,9 @@ QStringList CaptureFileDialog::buildFileSaveAsTypeList(bool must_support_all_com
ft = g_array_index(savable_file_types_subtypes, int, i);
if (default_ft_ < 1)
default_ft_ = ft; /* first file type is the default */
- file_type = fileType(ft);
- hash_file_type = fileType(ft, false);
- filters << file_type;
- type_hash_[hash_file_type] = ft;
+ QString type_name(wtap_file_type_subtype_string(ft));
+ filters << type_name + fileType(ft, type_suffixes_[type_name]);
+ type_hash_[type_name] = ft;
}
g_array_free(savable_file_types_subtypes, TRUE);
}
@@ -840,7 +901,7 @@ void CaptureFileDialog::on_buttonBox_helpRequested()
if (help_topic_ != TOPIC_ACTION_NONE) wsApp->helpTopicAction(help_topic_);
}
-#endif // Q_OS_WINDOWS
+#endif // ! Q_OS_WIN
/*
* Editor modelines