summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-01-25 13:49:21 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-02-02 11:26:17 +0100
commit9366e034d98c1588339a2f85c0e6d9cfc8ff18c4 (patch)
tree3d18d690f87ce3556208f1ff384cd6d0d8720fb3 /src/plugins
parenta3b58a7844f77bd416fad8307f8333ff7c0efacf (diff)
macOS: Use single variable to track file dialog in QCocoaFileDialogHelper
Relying on Objective-C's no-op behavior when sending messages to nil was nifty, but a bit confusing when trying to track the ownership model of the class. It's now explicit at the call sites what's going on (a cast). The canSelectHiddenExtension property is valid both save and open panels, but AppKit will only show it for save panels. Change-Id: I8e12d629639e2179d155b2ecda1bb2dab2a5757d Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm138
1 files changed, 74 insertions, 64 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 6ee1ad6093..51d8d76706 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -69,14 +69,22 @@ static NSString *strippedText(QString s)
return QPlatformTheme::removeMnemonics(s).trimmed().toNSString();
}
+// NSOpenPanel extends NSSavePanel with some extra APIs
+static NSOpenPanel *openpanel_cast(NSSavePanel *panel)
+{
+ if ([panel isKindOfClass:NSOpenPanel.class])
+ return static_cast<NSOpenPanel*>(panel);
+ else
+ return nil;
+}
+
typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
static const int kReturnCodeNotSet = -1;
@implementation QNSOpenSavePanelDelegate {
@public
- NSOpenPanel *m_openPanel;
- NSSavePanel *m_savePanel;
+ NSSavePanel *m_panel;
NSView *m_accessoryView;
NSPopUpButton *m_popupButton;
NSTextField *m_textField;
@@ -97,16 +105,14 @@ static const int kReturnCodeNotSet = -1;
{
if ((self = [super init])) {
m_options = options;
- if (m_options->acceptMode() == QFileDialogOptions::AcceptOpen){
- m_openPanel = [NSOpenPanel openPanel];
- m_savePanel = m_openPanel;
- } else {
- m_savePanel = [NSSavePanel savePanel];
- m_savePanel.canSelectHiddenExtension = YES;
- m_openPanel = nil;
- }
- m_savePanel.level = NSModalPanelWindowLevel;
+ if (m_options->acceptMode() == QFileDialogOptions::AcceptOpen)
+ m_panel = [[NSOpenPanel openPanel] retain];
+ else
+ m_panel = [[NSSavePanel savePanel] retain];
+
+ m_panel.canSelectHiddenExtension = YES;
+ m_panel.level = NSModalPanelWindowLevel;
m_returnCode = kReturnCodeNotSet;
m_helper = helper;
@@ -123,26 +129,27 @@ static const int kReturnCodeNotSet = -1;
m_currentSelection = new QString(sel.absoluteFilePath());
}
- m_savePanel.title = options->windowTitle().toNSString();
+ m_panel.title = options->windowTitle().toNSString();
[self createPopUpButton:selectedVisualNameFilter hideDetails:options->testOption(QFileDialogOptions::HideNameFilterDetails)];
[self createTextField];
[self createAccessory];
- m_savePanel.accessoryView = m_nameFilterDropDownList->size() > 1 ? m_accessoryView : nil;
+ m_panel.accessoryView = m_nameFilterDropDownList->size() > 1 ? m_accessoryView : nil;
// -setAccessoryView: can result in -panel:directoryDidChange:
// resetting our m_currentDirectory, set the delegate
// here to make sure it gets the correct value.
- m_savePanel.delegate = self;
- m_openPanel.accessoryViewDisclosed = YES;
+ m_panel.delegate = self;
+
+ if (auto *openPanel = openpanel_cast(m_panel))
+ openPanel.accessoryViewDisclosed = YES;
if (m_options->isLabelExplicitlySet(QFileDialogOptions::Accept))
- m_savePanel.prompt = strippedText(options->labelText(QFileDialogOptions::Accept));
+ m_panel.prompt = strippedText(options->labelText(QFileDialogOptions::Accept));
if (m_options->isLabelExplicitlySet(QFileDialogOptions::FileName))
- m_savePanel.nameFieldLabel = strippedText(options->labelText(QFileDialogOptions::FileName));
+ m_panel.nameFieldLabel = strippedText(options->labelText(QFileDialogOptions::FileName));
[self updateProperties];
- [m_savePanel retain];
}
return self;
}
@@ -153,27 +160,27 @@ static const int kReturnCodeNotSet = -1;
delete m_selectedNameFilter;
delete m_currentSelection;
- [m_savePanel orderOut:m_savePanel];
- m_savePanel.accessoryView = nil;
+ [m_panel orderOut:m_panel];
+ m_panel.accessoryView = nil;
[m_popupButton release];
[m_textField release];
[m_accessoryView release];
- m_savePanel.delegate = nil;
- [m_savePanel release];
+ m_panel.delegate = nil;
+ [m_panel release];
[m_currentDirectory release];
[super dealloc];
}
- (void)closePanel
{
- *m_currentSelection = QString::fromNSString(m_savePanel.URL.path).normalized(QString::NormalizationForm_C);
+ *m_currentSelection = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
- if (m_savePanel.sheet)
- [NSApp endSheet:m_savePanel];
- else if (NSApp.modalWindow == m_savePanel)
+ if (m_panel.sheet)
+ [NSApp endSheet:m_panel];
+ else if (NSApp.modalWindow == m_panel)
[NSApp stopModal];
else
- [m_savePanel close];
+ [m_panel close];
}
- (void)showModelessPanel
@@ -182,12 +189,12 @@ static const int kReturnCodeNotSet = -1;
NSString *filepath = info.filePath().toNSString();
NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:m_savePanel shouldEnableURL:url];
+ || [self panel:m_panel shouldEnableURL:url];
[self updateProperties];
- m_savePanel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
+ m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
- [m_savePanel beginWithCompletionHandler:^(NSInteger result){
+ [m_panel beginWithCompletionHandler:^(NSInteger result){
m_returnCode = result;
m_helper->panelClosed(result == NSModalResponseOK);
}];
@@ -199,10 +206,10 @@ static const int kReturnCodeNotSet = -1;
NSString *filepath = info.filePath().toNSString();
NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:m_savePanel shouldEnableURL:url];
+ || [self panel:m_panel shouldEnableURL:url];
- m_savePanel.directoryURL = [NSURL fileURLWithPath:m_currentDirectory];
- m_savePanel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
+ m_panel.directoryURL = [NSURL fileURLWithPath:m_currentDirectory];
+ m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
// Call processEvents in case the event dispatcher has been interrupted, and needs to do
// cleanup of modal sessions. Do this before showing the native dialog, otherwise it will
@@ -212,7 +219,7 @@ static const int kReturnCodeNotSet = -1;
// Make sure we don't interrupt the runModal call below.
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
- m_returnCode = [m_savePanel runModal];
+ m_returnCode = [m_panel runModal];
QAbstractEventDispatcher::instance()->interrupt();
return (m_returnCode == NSModalResponseOK);
@@ -224,15 +231,15 @@ static const int kReturnCodeNotSet = -1;
NSString *filepath = info.filePath().toNSString();
NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:m_savePanel shouldEnableURL:url];
+ || [self panel:m_panel shouldEnableURL:url];
[self updateProperties];
- m_savePanel.directoryURL = [NSURL fileURLWithPath:m_currentDirectory];
+ m_panel.directoryURL = [NSURL fileURLWithPath:m_currentDirectory];
- m_savePanel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
+ m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
NSWindow *nsparent = static_cast<NSWindow *>(qGuiApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parent));
- [m_savePanel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){
+ [m_panel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){
m_returnCode = result;
m_helper->panelClosed(result == NSModalResponseOK);
}];
@@ -267,7 +274,7 @@ static const int kReturnCodeNotSet = -1;
NSString *fileType = fileAttrs.fileType;
bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
if (isDir) {
- if (!m_savePanel.treatsFilePackagesAsDirectories) {
+ if (!m_panel.treatsFilePackagesAsDirectories) {
if ([NSWorkspace.sharedWorkspace isFilePackageAtPath:filename] == NO)
return YES;
}
@@ -315,9 +322,9 @@ static const int kReturnCodeNotSet = -1;
[m_popupButton addItemWithTitle:filter.toNSString()];
}
[m_popupButton selectItemAtIndex:0];
- m_savePanel.accessoryView = m_accessoryView;
+ m_panel.accessoryView = m_accessoryView;
} else {
- m_savePanel.accessoryView = nil;
+ m_panel.accessoryView = nil;
}
[self filterChanged:self];
@@ -329,7 +336,7 @@ static const int kReturnCodeNotSet = -1;
Q_UNUSED(sender);
QString selection = m_nameFilterDropDownList->value([m_popupButton indexOfSelectedItem]);
*m_selectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
- [m_savePanel validateVisibleColumns];
+ [m_panel validateVisibleColumns];
[self updateProperties];
const QStringList filters = m_options->nameFilters();
@@ -339,16 +346,16 @@ static const int kReturnCodeNotSet = -1;
- (QList<QUrl>)selectedFiles
{
- if (m_openPanel) {
+ if (auto *openPanel = openpanel_cast(m_panel)) {
QList<QUrl> result;
- for (NSURL *url in m_openPanel.URLs) {
+ for (NSURL *url in openPanel.URLs) {
QString path = QString::fromNSString(url.path).normalized(QString::NormalizationForm_C);
result << QUrl::fromLocalFile(path);
}
return result;
} else {
QList<QUrl> result;
- QString filename = QString::fromNSString(m_savePanel.URL.path).normalized(QString::NormalizationForm_C);
+ QString filename = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
const QString defaultSuffix = m_options->defaultSuffix();
const QFileInfo fileInfo(filename);
@@ -371,29 +378,32 @@ static const int kReturnCodeNotSet = -1;
|| fileMode == QFileDialogOptions::DirectoryOnly
|| m_options->testOption(QFileDialogOptions::ShowDirsOnly);
- m_openPanel.canChooseFiles = !chooseDirsOnly;
- m_openPanel.canChooseDirectories = !chooseFilesOnly;
- m_savePanel.canCreateDirectories = !(m_options->testOption(QFileDialogOptions::ReadOnly));
- m_openPanel.allowsMultipleSelection = (fileMode == QFileDialogOptions::ExistingFiles);
- m_openPanel.resolvesAliases = !(m_options->testOption(QFileDialogOptions::DontResolveSymlinks));
- m_savePanel.title = m_options->windowTitle().toNSString();
+ m_panel.title = m_options->windowTitle().toNSString();
+ m_panel.canCreateDirectories = !(m_options->testOption(QFileDialogOptions::ReadOnly));
+
+ if (auto *openPanel = openpanel_cast(m_panel)) {
+ openPanel.canChooseFiles = !chooseDirsOnly;
+ openPanel.canChooseDirectories = !chooseFilesOnly;
+ openPanel.allowsMultipleSelection = (fileMode == QFileDialogOptions::ExistingFiles);
+ openPanel.resolvesAliases = !(m_options->testOption(QFileDialogOptions::DontResolveSymlinks));
+ }
m_popupButton.hidden = chooseDirsOnly; // TODO hide the whole sunken pane instead?
if (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
[self recomputeAcceptableExtensionsForSave];
else
- m_openPanel.allowedFileTypes = nil; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel
+ m_panel.allowedFileTypes = nil; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel
- if (m_savePanel.visible)
- [m_savePanel validateVisibleColumns];
+ if (m_panel.visible)
+ [m_panel validateVisibleColumns];
}
- (void)panelSelectionDidChange:(id)sender
{
Q_UNUSED(sender);
- if (m_savePanel.visible) {
- QString selection = QString::fromNSString(m_savePanel.URL.path);
+ if (m_panel.visible) {
+ QString selection = QString::fromNSString(m_panel.URL.path);
if (selection != *m_currentSelection) {
*m_currentSelection = selection;
emit m_helper->currentChanged(QUrl::fromLocalFile(selection));
@@ -454,10 +464,10 @@ static const int kReturnCodeNotSet = -1;
// shown, so it will not have any effect when
// swithcing filters in an already opened dialog.
if (extensions.size() > 2)
- m_savePanel.extensionHidden = NO;
+ m_panel.extensionHidden = NO;
}
- m_savePanel.allowedFileTypes = fileTypes.isEmpty() ? nil
+ m_panel.allowedFileTypes = fileTypes.isEmpty() ? nil
: qt_mac_QStringListToNSMutableArray(fileTypes);
}
@@ -552,7 +562,7 @@ void QCocoaFileDialogHelper::panelClosed(bool accepted)
void QCocoaFileDialogHelper::setDirectory(const QUrl &directory)
{
if (m_delegate)
- m_delegate->m_savePanel.directoryURL = [NSURL fileURLWithPath:directory.toLocalFile().toNSString()];
+ m_delegate->m_panel.directoryURL = [NSURL fileURLWithPath:directory.toLocalFile().toNSString()];
else
m_directory = directory;
}
@@ -560,7 +570,7 @@ void QCocoaFileDialogHelper::setDirectory(const QUrl &directory)
QUrl QCocoaFileDialogHelper::directory() const
{
if (m_delegate) {
- QString path = QString::fromNSString(m_delegate->m_savePanel.directoryURL.path).normalized(QString::NormalizationForm_C);
+ QString path = QString::fromNSString(m_delegate->m_panel.directoryURL.path).normalized(QString::NormalizationForm_C);
return QUrl::fromLocalFile(path);
}
return m_directory;
@@ -589,11 +599,11 @@ void QCocoaFileDialogHelper::setFilter()
if (!m_delegate)
return;
const SharedPointerFileDialogOptions &opts = options();
- m_delegate->m_savePanel.title = opts->windowTitle().toNSString();
+ m_delegate->m_panel.title = opts->windowTitle().toNSString();
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
- m_delegate->m_savePanel.prompt = strippedText(opts->labelText(QFileDialogOptions::Accept));
+ m_delegate->m_panel.prompt = strippedText(opts->labelText(QFileDialogOptions::Accept));
if (opts->isLabelExplicitlySet(QFileDialogOptions::FileName))
- m_delegate->m_savePanel.nameFieldLabel = strippedText(opts->labelText(QFileDialogOptions::FileName));
+ m_delegate->m_panel.nameFieldLabel = strippedText(opts->labelText(QFileDialogOptions::FileName));
[m_delegate updateProperties];
}
@@ -681,7 +691,7 @@ void QCocoaFileDialogHelper::exec()
{
Q_ASSERT(m_delegate);
- if (m_delegate->m_savePanel.visible) {
+ if (m_delegate->m_panel.visible) {
// WindowModal or NonModal, so already shown above
QEventLoop eventLoop;
m_eventLoop = &eventLoop;