diff options
author | Tor Arne Vestbø <torarnv@gmail.com> | 2020-03-02 19:36:26 +0100 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2020-03-04 00:29:54 +0000 |
commit | 5d9d3ff3269f92366b022e17485fa4dd98f5ba95 (patch) | |
tree | 167204d917ad70ceb4c01538d5acac103aaded6d | |
parent | 1edf586ed73596e1d53a0d612a77f86ea34a65bf (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>
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm | 61 |
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 |