summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorTor Arne Vestbø <torarnv@gmail.com>2020-03-02 19:36:26 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2020-03-04 00:29:54 +0000
commit5d9d3ff3269f92366b022e17485fa4dd98f5ba95 (patch)
tree167204d917ad70ceb4c01538d5acac103aaded6d /src/plugins/platforms
parent1edf586ed73596e1d53a0d612a77f86ea34a65bf (diff)
macOS: Reduce save dialog extension filters to their last component
NSSavePanel does not deal well with multi-part extensions, to the point where it will fail to open if that's the only acceptable extension. We follow Chromium's lead here and reduce the extension to its last component, which enables selecting and saving files such as 'foo.tar.gz'. To improve the user experience we always show file extensions when we detect a multi-part extension. This makes it clearer what the final extension will be, and avoids confusing macOS about the intention of the user when choosing a file that without the final extension also matches another known extension. Fixes: QTBUG-38303 Fixes: QTBUG-44227 Change-Id: Id0cee84f758c2cd59fcf1b339caa30f7da07dd1e Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm61
1 files changed, 42 insertions, 19 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 6aa21d78d1..8b76e45616 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -419,8 +419,7 @@ static QString strippedText(QString s)
[mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead?
if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) {
- const QStringList ext = [self acceptableExtensionsForSave];
- [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)];
+ [self recomputeAcceptableExtensionsForSave];
} else {
[mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel
}
@@ -457,25 +456,49 @@ static QString strippedText(QString s)
}
/*
- Returns a list of extensions (e.g. "png", "jpg", "gif")
- for the current name filter. If a filter do not conform
- to the format *.xyz or * or *.*, an empty list
- is returned meaning accept everything.
+ Computes a list of extensions (e.g. "png", "jpg", "gif")
+ for the current name filter, and updates the save panel.
+
+ If a filter do not conform to the format *.xyz or * or *.*,
+ all files types are allowed.
+
+ Extensions with more than one part (e.g. "tar.gz") are
+ reduced to their final part, as NSSavePanel does not deal
+ well with multi-part extensions.
*/
-- (QStringList)acceptableExtensionsForSave
-{
- QStringList result;
- for (int i=0; i<mSelectedNameFilter->count(); ++i) {
- const QString &filter = mSelectedNameFilter->at(i);
- if (filter.startsWith(QLatin1String("*."))
- && !filter.contains(QLatin1Char('?'))
- && filter.count(QLatin1Char('*')) == 1) {
- result += filter.mid(2);
- } else {
- return QStringList(); // Accept everything
- }
+- (void)recomputeAcceptableExtensionsForSave
+{
+ QStringList fileTypes;
+ for (const QString &filter : *mSelectedNameFilter) {
+ if (!filter.startsWith(QLatin1String("*.")))
+ continue;
+
+ if (filter.contains(QLatin1Char('?')))
+ continue;
+
+ if (filter.count(QLatin1Char('*')) != 1)
+ continue;
+
+ auto extensions = filter.split('.', Qt::SkipEmptyParts);
+ fileTypes += extensions.last();
+
+ // Explicitly show extensions if we detect a filter
+ // that has a multi-part extension. This prevents
+ // confusing situations where the user clicks e.g.
+ // 'foo.tar.gz' and 'foo.tar' is populated in the
+ // file name box, but when then clicking save macOS
+ // will warn that the file needs to end in .gz,
+ // due to thinking the user tried to save the file
+ // as a 'tar' file instead. Unfortunately this
+ // property can only be set before the panel is
+ // shown, so it will not have any effect when
+ // swithcing filters in an already opened dialog.
+ if (extensions.size() > 2)
+ mSavePanel.extensionHidden = NO;
}
- return result;
+
+ mSavePanel.allowedFileTypes = fileTypes.isEmpty() ? nil
+ : qt_mac_QStringListToNSMutableArray(fileTypes);
}
- (QString)removeExtensions:(const QString &)filter