1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qcocoafiledialoghelper.h"
44 #ifndef QT_NO_FILEDIALOG
46 /*****************************************************************************
47 QFileDialog debug facilities
48 *****************************************************************************/
49 //#define DEBUG_FILEDIALOG_FILTERS
51 #include <qapplication.h>
52 #include <private/qapplication_p.h>
53 #include <private/qfiledialog_p.h>
54 #include <private/qt_mac_p.h>
55 #include <private/qt_cocoa_helpers_mac_p.h>
59 #include <qstringlist.h>
61 #include <qtextcodec.h>
62 #include <qvarlengtharray.h>
63 #include <qdesktopwidget.h>
65 #include <qabstracteventdispatcher.h>
66 #import <AppKit/NSSavePanel.h>
67 #include "ui_qfiledialog.h"
69 QT_FORWARD_DECLARE_CLASS(QFileDialogPrivate)
70 QT_FORWARD_DECLARE_CLASS(QString)
71 QT_FORWARD_DECLARE_CLASS(QStringList)
72 QT_FORWARD_DECLARE_CLASS(QWidget)
73 QT_FORWARD_DECLARE_CLASS(QAction)
74 QT_FORWARD_DECLARE_CLASS(QFileInfo)
75 QT_FORWARD_DECLARE_CLASS(QWindow)
78 typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
80 @class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
82 @interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
83 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
84 : NSObject<NSOpenSavePanelDelegate>
90 NSOpenPanel *mOpenPanel;
91 NSSavePanel *mSavePanel;
92 NSView *mAccessoryView;
93 NSPopUpButton *mPopUpButton;
94 NSTextField *mTextField;
95 QFileDialog *mFileDialog;
96 QCocoaFileDialogHelper *mHelper;
97 NSString *mCurrentDir;
101 SharedPointerFileDialogOptions mOptions;
102 QString *mLastFilterCheckPath;
103 QString *mCurrentSelection;
104 QStringList *mQDirFilterEntryList;
105 QStringList *mNameFilterDropDownList;
106 QStringList *mSelectedNameFilter;
109 - (NSString *)strip:(const QString &)label;
110 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
111 - (void)filterChanged:(id)sender;
112 - (void)showModelessPanel;
113 - (BOOL)runApplicationModalPanel;
114 - (void)showWindowModalSheet:(QWindow *)docWidget;
115 - (void)updateProperties;
116 - (QStringList)acceptableExtensionsForSave;
117 - (QString)removeExtensions:(const QString &)filter;
118 - (void)createTextField;
119 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails;
120 - (QStringList)findStrippedFilterWithVisualFilterName:(QString)name;
121 - (void)createAccessory;
125 @implementation QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
127 - (id)initWithAcceptMode:
128 (const QString &)selectFile
129 fileDialog:(QFileDialog *)fileDialog
130 options:(SharedPointerFileDialogOptions)options
131 helper:(QCocoaFileDialogHelper *)helper
134 mFileDialog = fileDialog;
136 if (mOptions->acceptMode() == QT_PREPEND_NAMESPACE(QFileDialogOptions::AcceptOpen)){
137 mOpenPanel = [NSOpenPanel openPanel];
138 mSavePanel = mOpenPanel;
140 mSavePanel = [NSSavePanel savePanel];
141 [mSavePanel setCanSelectHiddenExtension:YES];
145 [mSavePanel setLevel:NSModalPanelWindowLevel];
146 [mSavePanel setDelegate:self];
149 mLastFilterCheckPath = new QString;
150 mQDirFilterEntryList = new QStringList;
151 mNameFilterDropDownList = new QStringList(mOptions->nameFilters());
152 QString selectedVisualNameFilter = mFileDialog->selectedNameFilter();
153 mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
155 QFileInfo sel(selectFile);
157 mCurrentDir = [qt_mac_QStringToNSString(sel.absoluteFilePath()) retain];
158 mCurrentSelection = new QString;
160 mCurrentDir = [qt_mac_QStringToNSString(sel.absolutePath()) retain];
161 mCurrentSelection = new QString(sel.absoluteFilePath());
164 [mSavePanel setTitle:qt_mac_QStringToNSString(options->windowTitle())];
165 [self createPopUpButton:selectedVisualNameFilter hideDetails:options->testOption(QFileDialogOptions::HideNameFilterDetails)];
166 [self createTextField];
167 [self createAccessory];
168 [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
171 if (mOptions->isLabelExplicitlySet(QFileDialogOptions::Accept))
172 [mSavePanel setPrompt:[self strip:options->labelText(QFileDialogOptions::Accept)]];
173 if (mOptions->isLabelExplicitlySet(QFileDialogOptions::FileName))
174 [mSavePanel setNameFieldLabel:[self strip:options->labelText(QFileDialogOptions::FileName)]];
176 [self updateProperties];
183 delete mLastFilterCheckPath;
184 delete mQDirFilterEntryList;
185 delete mNameFilterDropDownList;
186 delete mSelectedNameFilter;
187 delete mCurrentSelection;
189 [mSavePanel orderOut:mSavePanel];
190 [mSavePanel setAccessoryView:nil];
191 [mPopUpButton release];
192 [mTextField release];
193 [mAccessoryView release];
194 [mSavePanel setDelegate:nil];
195 [mSavePanel release];
196 [mCurrentDir release];
200 - (NSString *)strip:(const QString &)label
203 return qt_mac_QStringToNSString(a.iconText());
208 *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
212 - (void)showModelessPanel
215 QFileInfo info(*mCurrentSelection);
216 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
217 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
218 bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
219 || [self panel:nil shouldShowFilename:filepath];
221 beginForDirectory:mCurrentDir
222 file:selectable ? filename : nil
224 modelessDelegate:self
225 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
230 - (BOOL)runApplicationModalPanel
232 QFileInfo info(*mCurrentSelection);
233 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
234 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
235 bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
236 || [self panel:nil shouldShowFilename:filepath];
237 mReturnCode = [mSavePanel
238 runModalForDirectory:mCurrentDir
239 file:selectable ? filename : @"untitled"];
241 QAbstractEventDispatcher::instance()->interrupt();
242 return (mReturnCode == NSOKButton);
245 - (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode
247 return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected);
250 - (void)showWindowModalSheet:(QWindow *)docWidget
253 QFileInfo info(*mCurrentSelection);
254 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
255 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
256 bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
257 || [self panel:nil shouldShowFilename:filepath];
259 beginSheetForDirectory:mCurrentDir
260 file:selectable ? filename : nil
263 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
267 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
271 if ([filename length] == 0)
274 // Always accept directories regardless of their names (unless it is a bundle):
276 if ([[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir] && isDir) {
277 if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
278 if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
283 QString qtFileName = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename);
284 QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C)));
285 QString path = info.absolutePath();
286 if (path != *mLastFilterCheckPath){
287 *mLastFilterCheckPath = path;
288 *mQDirFilterEntryList = info.dir().entryList(mOptions->filter());
290 // Check if the QDir filter accepts the file:
291 if (!mQDirFilterEntryList->contains(info.fileName()))
294 // No filter means accept everything
295 if (mSelectedNameFilter->isEmpty())
297 // Check if the current file name filter accepts the file:
298 for (int i=0; i<mSelectedNameFilter->size(); ++i) {
299 if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
305 - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
310 if (!mOptions->testOption(QFileDialogOptions::DontConfirmOverwrite))
313 // User has clicked save, and no overwrite confirmation should occur.
314 // To get the latter, we need to change the name we return (hence the prefix):
315 return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
318 - (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
320 [mPopUpButton removeAllItems];
321 *mNameFilterDropDownList = filters;
322 if (filters.size() > 0){
323 for (int i=0; i<filters.size(); ++i) {
324 QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
325 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
327 [mPopUpButton selectItemAtIndex:0];
328 [mSavePanel setAccessoryView:mAccessoryView];
330 [mSavePanel setAccessoryView:nil];
332 [self filterChanged:self];
335 - (void)filterChanged:(id)sender
337 // This mDelegate function is called when the _name_ filter changes.
339 QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
340 *mSelectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
341 [mSavePanel validateVisibleColumns];
342 [self updateProperties];
344 mHelper->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
347 - (QString)currentNameFilter
349 return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
352 - (QStringList)selectedFiles
355 return QT_PREPEND_NAMESPACE(qt_mac_NSArrayToQStringList)([mOpenPanel filenames]);
358 QString filename = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
359 result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_"));
364 - (void)updateProperties
366 // Call this functions if mFileMode, mFileOptions,
367 // mNameFilterDropDownList or mQDirFilter changes.
368 // The savepanel does not contain the neccessary functions for this.
369 const QT_PREPEND_NAMESPACE(QFileDialogOptions::FileMode) fileMode = mOptions->fileMode();
370 bool chooseFilesOnly = fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFile)
371 || fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles);
372 bool chooseDirsOnly = fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::Directory)
373 || fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::DirectoryOnly)
374 || mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ShowDirsOnly));
376 [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
377 [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
378 [mSavePanel setCanCreateDirectories:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ReadOnly)))];
379 [mOpenPanel setAllowsMultipleSelection:(fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles))];
380 [mOpenPanel setResolvesAliases:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::DontResolveSymlinks)))];
382 QStringList ext = [self acceptableExtensionsForSave];
383 const QString defaultSuffix = mOptions->defaultSuffix();
384 if (!ext.isEmpty() && !defaultSuffix.isEmpty())
385 ext.prepend(defaultSuffix);
386 [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))];
388 if ([mSavePanel isVisible])
389 [mOpenPanel validateVisibleColumns];
392 - (void)panelSelectionDidChange:(id)sender
396 QString selection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString([mSavePanel filename]));
397 if (selection != mCurrentSelection) {
398 *mCurrentSelection = selection;
399 mHelper->QNSOpenSavePanelDelegate_selectionChanged(selection);
404 - (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
407 Q_UNUSED(contextInfo);
408 mReturnCode = returnCode;
410 mHelper->QNSOpenSavePanelDelegate_panelClosed(returnCode == NSOKButton);
413 - (void)panel:(id)sender directoryDidChange:(NSString *)path
418 if ([path isEqualToString:mCurrentDir])
421 [mCurrentDir release];
422 mCurrentDir = [path retain];
423 mHelper->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString(mCurrentDir)));
427 Returns a list of extensions (e.g. "png", "jpg", "gif")
428 for the current name filter. If a filter do not conform
429 to the format *.xyz or * or *.*, an empty list
430 is returned meaning accept everything.
432 - (QStringList)acceptableExtensionsForSave
435 for (int i=0; i<mSelectedNameFilter->count(); ++i) {
436 const QString &filter = mSelectedNameFilter->at(i);
437 if (filter.startsWith(QLatin1String("*."))
438 && !filter.contains(QLatin1Char('?'))
439 && filter.count(QLatin1Char('*')) == 1) {
440 result += filter.mid(2);
442 return QStringList(); // Accept everything
448 - (QString)removeExtensions:(const QString &)filter
450 QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(QFileDialogPrivate::qt_file_dialog_filter_reg_exp)));
451 if (regExp.indexIn(filter) != -1)
452 return regExp.cap(1).trimmed();
456 - (void)createTextField
458 NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
459 mTextField = [[NSTextField alloc] initWithFrame:textRect];
460 [[mTextField cell] setFont:[NSFont systemFontOfSize:
461 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
462 [mTextField setAlignment:NSRightTextAlignment];
463 [mTextField setEditable:false];
464 [mTextField setSelectable:false];
465 [mTextField setBordered:false];
466 [mTextField setDrawsBackground:false];
467 if (mOptions->isLabelExplicitlySet(QFileDialogOptions::FileType))
468 [mTextField setStringValue:[self strip:mOptions->labelText(QFileDialogOptions::FileType)]];
471 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
473 NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
474 mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
475 [mPopUpButton setTarget:self];
476 [mPopUpButton setAction:@selector(filterChanged:)];
478 QStringList *filters = mNameFilterDropDownList;
479 if (filters->size() > 0){
480 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
481 QString filter = hideDetails ? [self removeExtensions:filters->at(i)] : filters->at(i);
482 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
483 if (filters->at(i).startsWith(selectedFilter))
484 [mPopUpButton selectItemAtIndex:i];
489 - (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
491 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
492 if (mNameFilterDropDownList->at(i).startsWith(name))
493 return QFileDialogPrivate::qt_clean_filter_list(mNameFilterDropDownList->at(i));
495 return QStringList();
498 - (void)createAccessory
500 NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
501 mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
502 [mAccessoryView addSubview:mTextField];
503 [mAccessoryView addSubview:mPopUpButton];
510 static bool qt_mac_is_macsheet(const QWidget *w)
515 Qt::WindowModality modality = w->windowModality();
516 if (modality == Qt::ApplicationModal)
518 return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet);
521 QCocoaFileDialogHelper::QCocoaFileDialogHelper(QFileDialog *dialog) :
522 qtFileDialog(dialog), mDelegate(0)
526 QCocoaFileDialogHelper::~QCocoaFileDialogHelper()
531 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
533 emit currentChanged(newPath);
536 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
545 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
547 // ### fixme: priv->setLastVisitedDirectory(newDir);
548 emit directoryEntered(newDir);
551 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
553 const QStringList filters = options()->nameFilters();
554 emit filterSelected(menuIndex >= 0 && menuIndex < filters.size() ? filters.at(menuIndex) : QString());
557 extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp
558 extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp
560 void QCocoaFileDialogHelper::setDirectory_sys(const QString &directory)
562 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
563 [delegate->mSavePanel setDirectory:qt_mac_QStringToNSString(directory)];
566 QString QCocoaFileDialogHelper::directory_sys() const
568 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
569 return qt_mac_NSStringToQString([delegate->mSavePanel directory]);
572 void QCocoaFileDialogHelper::selectFile_sys(const QString &filename)
574 QString filePath = filename;
575 if (QDir::isRelativePath(filePath))
576 filePath = QFileInfo(directory_sys(), filePath).filePath();
578 // There seems to no way to select a file once the dialog is running.
579 // So do the next best thing, set the file's directory:
580 setDirectory_sys(QFileInfo(filePath).absolutePath());
583 QStringList QCocoaFileDialogHelper::selectedFiles_sys() const
585 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
586 return [delegate selectedFiles];
589 void QCocoaFileDialogHelper::setFilter_sys()
591 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
592 const SharedPointerFileDialogOptions &opts = options();
593 [delegate->mSavePanel setTitle:qt_mac_QStringToNSString(opts->windowTitle())];
594 if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
595 [delegate->mSavePanel setPrompt:[delegate strip:opts->labelText(QFileDialogOptions::Accept)]];
596 if (opts->isLabelExplicitlySet(QFileDialogOptions::FileName))
597 [delegate->mSavePanel setNameFieldLabel:[delegate strip:opts->labelText(QFileDialogOptions::FileName)]];
599 [delegate updateProperties];
602 void QCocoaFileDialogHelper::selectNameFilter_sys(const QString &filter)
604 const int index = options()->nameFilters().indexOf(filter);
606 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
607 [delegate->mPopUpButton selectItemAtIndex:index];
608 [delegate filterChanged:nil];
612 QString QCocoaFileDialogHelper::selectedNameFilter_sys() const
614 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
615 int index = [delegate->mPopUpButton indexOfSelectedItem];
616 return index != -1 ? options()->nameFilters().at(index) : QString();
619 void QCocoaFileDialogHelper::deleteNativeDialog_sys()
621 [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release];
625 void QCocoaFileDialogHelper::hide_sys()
627 if (!qtFileDialog->isHidden())
628 hideCocoaFilePanel();
631 bool QCocoaFileDialogHelper::show_sys(ShowFlags /* flags */, Qt::WindowFlags windowFlags, QWindow *parent)
634 if (!qtFileDialog->isHidden())
637 if (windowFlags & Qt::WindowStaysOnTopHint) {
638 // The native file dialog tries all it can to stay
639 // on the NSModalPanel level. And it might also show
640 // its own "create directory" dialog that we cannot control.
641 // So we need to use the non-native version in this case...
645 return showCocoaFilePanel(parent);
648 void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate()
652 const SharedPointerFileDialogOptions &opts = options();
653 const QStringList selectedFiles = opts->initiallySelectedFiles();
654 const QString directory = opts->initialDirectory();
655 const bool selectDir = selectedFiles.isEmpty();
656 QString selection(selectDir ? directory : selectedFiles.front());
657 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc]
660 fileDialog:qtFileDialog
664 mDelegate = delegate;
667 bool QCocoaFileDialogHelper::showCocoaFilePanel(QWindow *parent)
670 createNSOpenSavePanelDelegate();
671 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
672 if (qt_mac_is_macsheet(qtFileDialog))
673 [delegate showWindowModalSheet:parent];
675 [delegate showModelessPanel];
679 bool QCocoaFileDialogHelper::hideCocoaFilePanel()
682 // Nothing to do. We return false to leave the question
683 // open regarding whether or not to go native:
686 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
687 [delegate closePanel];
688 // Even when we hide it, we are still using a
689 // native dialog, so return true:
694 void QCocoaFileDialogHelper::platformNativeDialogModalHelp()
696 // Do a queued meta-call to open the native modal dialog so it opens after the new
697 // event loop has started to execute (in QDialog::exec). Using a timer rather than
698 // a queued meta call is intentional to ensure that the call is only delivered when
699 // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
700 // running (which is the case if e.g a top-most QEventLoop has been
701 // interrupted, and the second-most event loop has not yet been reactivated (regardless
702 // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
703 QTimer::singleShot(1, this, SIGNAL(launchNativeAppModalPanel()));
706 void QCocoaFileDialogHelper::_q_platformRunNativeAppModalPanel()
710 QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
712 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
713 [delegate runApplicationModalPanel];
714 if (dialogResultCode_sys() == QPlatformDialogHelper::Accepted)
720 QPlatformDialogHelper::DialogCode QCocoaFileDialogHelper::dialogResultCode_sys()
722 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
723 return [delegate dialogResultCode];
726 bool QCocoaFileDialogHelper::defaultNameFilterDisables() const
733 #endif // QT_NO_FILEDIALOG