Details
-
Bug
-
Resolution: Out of scope
-
P1: Critical
-
None
-
5.9, 5.12, 5.14
-
None
-
macOS 10.15 (Catalina)
Description
In macOS 10.15 (Catalina), the native Cocoa file save dialog will crash if all of the following are true:
- the user confirms the default filename without modifying it
- an extension is automatically added to the filename based on the selected filter
- a file with the same name already exists
- the user chooses to replace the file when prompted by macOS.
The following program demonstrates the problem:
#include <QApplication> #include <QFileDialog> int main(int argc, char **argv) { QApplication app(argc, argv); QWidget window; QString caption = "Save As"; QString filter = "Plain text (*.txt);;Markdown (*.md)"; QString path = "Untitled.txt"; QString selectedFilter; QFileDialog::Options options = QFileDialog::Options(); path = QFileDialog::getSaveFileName(&window, caption, path, filter, &selectedFilter, options); QFile f(path); f.open(QIODevice::WriteOnly); f.close(); path = QFileDialog::getSaveFileName(&window, caption, path, filter, &selectedFilter, options); }
The above program will prompt the user for a filename. If the file exists, and the user agrees to replace the file, the program will crash before the first call to QFileDialog::getSaveFileName() returns. Otherwise, the file will be created. Then the program will once again prompt the user for a filename. Assuming the file creation was successful, if the user chooses the same filename and agrees to replace the file, the program will crash.
I noticed that QNSOpenSavePanelDelegate does not implement the panel:validateURL:error: instance method of the NSOpenSavePanelDelegate protocol. Adding an implementation of this method in
qtbase/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
seems to solve the problem. It can be as simple as this:
- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError { Q_UNUSED(sender); Q_UNUSED(url); Q_UNUSED(outError); return YES; }
At first, my thought was to retain a reference to the NSURL passed to this method, and use that instead of calling [mSavePanel URL], since that seemed to be where the assertion failure was, but I found that simply providing an implementation of this method allowed the calls to [mSavePanel URL] to succeed.
To be fair, I see this more as a bug in Catalina than in Qt, but I think it would be good to implement this method of the NSOpenSavePanelDelegate protocol, especially since it seems to resolve this issue.