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)
77 @class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
79 @interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
80 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
81 : NSObject<NSOpenSavePanelDelegate>
87 NSOpenPanel *mOpenPanel;
88 NSSavePanel *mSavePanel;
89 NSView *mAccessoryView;
90 NSPopUpButton *mPopUpButton;
91 NSTextField *mTextField;
92 QFileDialog *mFileDialog;
93 QCocoaFileDialogHelper *mHelper;
94 NSString *mCurrentDir;
95 bool mConfirmOverwrite;
98 QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode) mAcceptMode;
99 QT_PREPEND_NAMESPACE(QDir::Filters) *mQDirFilter;
100 QT_PREPEND_NAMESPACE(QFileDialog::FileMode) mFileMode;
101 QT_PREPEND_NAMESPACE(QFileDialog::Options) *mFileOptions;
103 QString *mLastFilterCheckPath;
104 QString *mCurrentSelection;
105 QStringList *mQDirFilterEntryList;
106 QStringList *mNameFilterDropDownList;
107 QStringList *mSelectedNameFilter;
110 - (NSString *)strip:(const QString &)label;
111 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
112 - (void)filterChanged:(id)sender;
113 - (void)showModelessPanel;
114 - (BOOL)runApplicationModalPanel;
115 - (void)showWindowModalSheet:(QWidget *)docWidget;
116 - (void)updateProperties;
117 - (QStringList)acceptableExtensionsForSave;
118 - (QString)removeExtensions:(const QString &)filter;
119 - (void)createTextField;
120 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails;
121 - (QStringList)findStrippedFilterWithVisualFilterName:(QString)name;
122 - (void)createAccessory;
126 @implementation QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
128 - (id)initWithAcceptMode:(QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode))acceptMode
129 title:(const QString &)title
130 hideNameFilterDetails:(bool)hideNameFilterDetails
131 qDirFilter:(QT_PREPEND_NAMESPACE(QDir::Filters))qDirFilter
132 fileOptions:(QT_PREPEND_NAMESPACE(QFileDialog::Options))fileOptions
133 fileMode:(QT_PREPEND_NAMESPACE(QFileDialog::FileMode))fileMode
134 selectFile:(const QString &)selectFile
135 confirmOverwrite:(bool)confirm
136 fileDialog:(QFileDialog *)fileDialog
137 helper:(QCocoaFileDialogHelper *)helper
140 mFileDialog = fileDialog;
141 mAcceptMode = acceptMode;
142 if (mAcceptMode == QT_PREPEND_NAMESPACE(QFileDialog::AcceptOpen)){
143 mOpenPanel = [NSOpenPanel openPanel];
144 mSavePanel = mOpenPanel;
146 mSavePanel = [NSSavePanel savePanel];
150 [mSavePanel setLevel:NSModalPanelWindowLevel];
151 [mSavePanel setDelegate:self];
152 mQDirFilter = new QT_PREPEND_NAMESPACE(QDir::Filters)(qDirFilter);
153 mFileOptions = new QT_PREPEND_NAMESPACE(QFileDialog::Options)(fileOptions);
154 mFileMode = fileMode;
155 mConfirmOverwrite = confirm;
158 mLastFilterCheckPath = new QString;
159 mQDirFilterEntryList = new QStringList;
160 mNameFilterDropDownList = new QStringList(mFileDialog->nameFilters());
161 QString selectedVisualNameFilter = mFileDialog->selectedNameFilter();
162 mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
164 QFileInfo sel(selectFile);
166 mCurrentDir = [qt_mac_QStringToNSString(sel.absoluteFilePath()) retain];
167 mCurrentSelection = new QString;
169 mCurrentDir = [qt_mac_QStringToNSString(sel.absolutePath()) retain];
170 mCurrentSelection = new QString(sel.absoluteFilePath());
173 [mSavePanel setTitle:qt_mac_QStringToNSString(title)];
174 [self createPopUpButton:selectedVisualNameFilter hideDetails:hideNameFilterDetails];
175 [self createTextField];
176 [self createAccessory];
177 [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
180 [mSavePanel setPrompt:[self strip:mFileDialog->labelText(QFileDialog::Accept)]];
181 if (false) // ### fixme mPriv->fileNameLabelExplicitlySat)
182 [mSavePanel setNameFieldLabel:[self strip:mFileDialog->labelText(QFileDialog::FileName)]];
184 [self updateProperties];
193 delete mLastFilterCheckPath;
194 delete mQDirFilterEntryList;
195 delete mNameFilterDropDownList;
196 delete mSelectedNameFilter;
197 delete mCurrentSelection;
199 [mSavePanel orderOut:mSavePanel];
200 [mSavePanel setAccessoryView:nil];
201 [mPopUpButton release];
202 [mTextField release];
203 [mAccessoryView release];
204 [mSavePanel setDelegate:nil];
205 [mSavePanel release];
206 [mCurrentDir release];
210 - (NSString *)strip:(const QString &)label
213 return qt_mac_QStringToNSString(a.iconText());
218 *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
222 - (void)showModelessPanel
225 QFileInfo info(*mCurrentSelection);
226 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
227 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
228 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
229 || [self panel:nil shouldShowFilename:filepath];
231 beginForDirectory:mCurrentDir
232 file:selectable ? filename : nil
234 modelessDelegate:self
235 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
240 - (BOOL)runApplicationModalPanel
242 QFileInfo info(*mCurrentSelection);
243 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
244 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
245 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
246 || [self panel:nil shouldShowFilename:filepath];
247 mReturnCode = [mSavePanel
248 runModalForDirectory:mCurrentDir
249 file:selectable ? filename : @"untitled"];
251 QAbstractEventDispatcher::instance()->interrupt();
252 return (mReturnCode == NSOKButton);
255 - (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode
257 return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected);
260 - (void)showWindowModalSheet:(QWidget *)docWidget
263 QFileInfo info(*mCurrentSelection);
264 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
265 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
266 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
267 || [self panel:nil shouldShowFilename:filepath];
269 beginSheetForDirectory:mCurrentDir
270 file:selectable ? filename : nil
273 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
277 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
281 if ([filename length] == 0)
284 // Always accept directories regardless of their names (unless it is a bundle):
286 if ([[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir] && isDir) {
287 if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
288 if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
293 QString qtFileName = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename);
294 QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C)));
295 QString path = info.absolutePath();
296 if (path != *mLastFilterCheckPath){
297 *mLastFilterCheckPath = path;
298 *mQDirFilterEntryList = info.dir().entryList(*mQDirFilter);
300 // Check if the QDir filter accepts the file:
301 if (!mQDirFilterEntryList->contains(info.fileName()))
304 // No filter means accept everything
305 if (mSelectedNameFilter->isEmpty())
307 // Check if the current file name filter accepts the file:
308 for (int i=0; i<mSelectedNameFilter->size(); ++i) {
309 if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
315 - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
320 if (mConfirmOverwrite)
323 // User has clicked save, and no overwrite confirmation should occur.
324 // To get the latter, we need to change the name we return (hence the prefix):
325 return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
328 - (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
330 [mPopUpButton removeAllItems];
331 *mNameFilterDropDownList = filters;
332 if (filters.size() > 0){
333 for (int i=0; i<filters.size(); ++i) {
334 QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
335 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
337 [mPopUpButton selectItemAtIndex:0];
338 [mSavePanel setAccessoryView:mAccessoryView];
340 [mSavePanel setAccessoryView:nil];
342 [self filterChanged:self];
345 - (void)filterChanged:(id)sender
347 // This mDelegate function is called when the _name_ filter changes.
349 QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
350 *mSelectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
351 [mSavePanel validateVisibleColumns];
352 [self updateProperties];
354 mHelper->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
357 - (QString)currentNameFilter
359 return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
362 - (QStringList)selectedFiles
365 return QT_PREPEND_NAMESPACE(qt_mac_NSArrayToQStringList)([mOpenPanel filenames]);
368 QString filename = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
369 result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_"));
374 - (void)updateProperties
376 // Call this functions if mFileMode, mFileOptions,
377 // mNameFilterDropDownList or mQDirFilter changes.
378 // The savepanel does not contain the neccessary functions for this.
379 bool chooseFilesOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFile)
380 || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles);
381 bool chooseDirsOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::Directory)
382 || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::DirectoryOnly)
383 || *mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ShowDirsOnly);
385 [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
386 [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
387 [mSavePanel setCanCreateDirectories:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ReadOnly))];
388 [mOpenPanel setAllowsMultipleSelection:(mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles))];
389 [mOpenPanel setResolvesAliases:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::DontResolveSymlinks))];
391 QStringList ext = [self acceptableExtensionsForSave];
392 const QString defaultSuffix = mFileDialog->defaultSuffix();
393 if (!ext.isEmpty() && !defaultSuffix.isEmpty())
394 ext.prepend(defaultSuffix);
395 [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))];
397 if ([mSavePanel isVisible])
398 [mOpenPanel validateVisibleColumns];
401 - (void)panelSelectionDidChange:(id)sender
405 QString selection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString([mSavePanel filename]));
406 if (selection != mCurrentSelection) {
407 *mCurrentSelection = selection;
408 mHelper->QNSOpenSavePanelDelegate_selectionChanged(selection);
413 - (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
416 Q_UNUSED(contextInfo);
417 mReturnCode = returnCode;
419 mHelper->QNSOpenSavePanelDelegate_panelClosed(returnCode == NSOKButton);
422 - (void)panel:(id)sender directoryDidChange:(NSString *)path
427 if ([path isEqualToString:mCurrentDir])
430 [mCurrentDir release];
431 mCurrentDir = [path retain];
432 mHelper->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString(mCurrentDir)));
436 Returns a list of extensions (e.g. "png", "jpg", "gif")
437 for the current name filter. If a filter do not conform
438 to the format *.xyz or * or *.*, an empty list
439 is returned meaning accept everything.
441 - (QStringList)acceptableExtensionsForSave
444 for (int i=0; i<mSelectedNameFilter->count(); ++i) {
445 const QString &filter = mSelectedNameFilter->at(i);
446 if (filter.startsWith(QLatin1String("*."))
447 && !filter.contains(QLatin1Char('?'))
448 && filter.count(QLatin1Char('*')) == 1) {
449 result += filter.mid(2);
451 return QStringList(); // Accept everything
457 - (QString)removeExtensions:(const QString &)filter
459 QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(QFileDialogPrivate::qt_file_dialog_filter_reg_exp)));
460 if (regExp.indexIn(filter) != -1)
461 return regExp.cap(1).trimmed();
465 - (void)createTextField
467 NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
468 mTextField = [[NSTextField alloc] initWithFrame:textRect];
469 [[mTextField cell] setFont:[NSFont systemFontOfSize:
470 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
471 [mTextField setAlignment:NSRightTextAlignment];
472 [mTextField setEditable:false];
473 [mTextField setSelectable:false];
474 [mTextField setBordered:false];
475 [mTextField setDrawsBackground:false];
476 [mTextField setStringValue:[self strip:mFileDialog->labelText(QFileDialog::FileType)]];
479 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
481 NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
482 mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
483 [mPopUpButton setTarget:self];
484 [mPopUpButton setAction:@selector(filterChanged:)];
486 QStringList *filters = mNameFilterDropDownList;
487 if (filters->size() > 0){
488 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
489 QString filter = hideDetails ? [self removeExtensions:filters->at(i)] : filters->at(i);
490 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
491 if (filters->at(i).startsWith(selectedFilter))
492 [mPopUpButton selectItemAtIndex:i];
497 - (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
499 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
500 if (mNameFilterDropDownList->at(i).startsWith(name))
501 return QFileDialogPrivate::qt_clean_filter_list(mNameFilterDropDownList->at(i));
503 return QStringList();
506 - (void)createAccessory
508 NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
509 mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
510 [mAccessoryView addSubview:mTextField];
511 [mAccessoryView addSubview:mPopUpButton];
518 static bool qt_mac_is_macsheet(const QWidget *w)
523 Qt::WindowModality modality = w->windowModality();
524 if (modality == Qt::ApplicationModal)
526 return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet);
529 QCocoaFileDialogHelper::QCocoaFileDialogHelper(QFileDialog *dialog) :
530 qtFileDialog(dialog), mDelegate(0)
534 QCocoaFileDialogHelper::~QCocoaFileDialogHelper()
539 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
541 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "currentChanged", Q_ARG(QString, newPath));
544 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
547 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "accept");
549 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "reject");
552 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
554 // ### fixme: priv->setLastVisitedDirectory(newDir);
555 emit directoryEntered(newDir);
558 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
560 const QStringList filters = qtFileDialog->nameFilters();
561 emit filterSelected(menuIndex >= 0 && menuIndex < filters.size() ? filters.at(menuIndex) : QString());
564 extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp
565 extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp
567 void QCocoaFileDialogHelper::setDirectory_sys(const QString &directory)
569 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
570 [delegate->mSavePanel setDirectory:qt_mac_QStringToNSString(directory)];
573 QString QCocoaFileDialogHelper::directory_sys() const
575 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
576 return qt_mac_NSStringToQString([delegate->mSavePanel directory]);
579 void QCocoaFileDialogHelper::selectFile_sys(const QString &filename)
581 QString filePath = filename;
582 if (QDir::isRelativePath(filePath))
583 filePath = QFileInfo(directory_sys(), filePath).filePath();
585 // There seems to no way to select a file once the dialog is running.
586 // So do the next best thing, set the file's directory:
587 setDirectory_sys(QFileInfo(filePath).absolutePath());
590 QStringList QCocoaFileDialogHelper::selectedFiles_sys() const
592 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
593 return [delegate selectedFiles];
596 void QCocoaFileDialogHelper::setNameFilters_sys(const QStringList &filters)
598 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
599 bool hideDetails = qtFileDialog->testOption(QFileDialog::HideNameFilterDetails);
600 [delegate setNameFilters:filters hideDetails:hideDetails];
603 void QCocoaFileDialogHelper::setFilter_sys()
605 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
606 *(delegate->mQDirFilter) = qtFileDialog->filter();
607 delegate->mFileMode = qtFileDialog->fileMode();
608 [delegate->mSavePanel setTitle:qt_mac_QStringToNSString(qtFileDialog->windowTitle())];
609 [delegate->mSavePanel setPrompt:[delegate strip:qtFileDialog->labelText(QFileDialog::Accept)]];
610 if (false) // ### fixme priv->fileNameLabelExplicitlySat)
611 [delegate->mSavePanel setNameFieldLabel:[delegate strip:qtFileDialog->labelText(QFileDialog::FileName)]];
613 [delegate updateProperties];
616 void QCocoaFileDialogHelper::selectNameFilter_sys(const QString &filter)
618 const int index = qtFileDialog->nameFilters().indexOf(filter);
620 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
621 [delegate->mPopUpButton selectItemAtIndex:index];
622 [delegate filterChanged:nil];
626 QString QCocoaFileDialogHelper::selectedNameFilter_sys() const
628 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
629 int index = [delegate->mPopUpButton indexOfSelectedItem];
630 return index != -1 ? qtFileDialog->nameFilters().at(index) : QString();
633 void QCocoaFileDialogHelper::deleteNativeDialog_sys()
635 [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release];
639 void QCocoaFileDialogHelper::hide_sys()
641 if (!qtFileDialog->isHidden())
642 hideCocoaFilePanel();
645 bool QCocoaFileDialogHelper::show_sys(QWindow * /* parent */)
648 if (!qtFileDialog->isHidden())
651 if (qtFileDialog->windowFlags() & Qt::WindowStaysOnTopHint) {
652 // The native file dialog tries all it can to stay
653 // on the NSModalPanel level. And it might also show
654 // its own "create directory" dialog that we cannot control.
655 // So we need to use the non-native version in this case...
659 return showCocoaFilePanel();
662 void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate()
667 bool selectDir = qtFileDialog->selectedFiles().isEmpty();
668 QString selection(selectDir ? qtFileDialog->directory().absolutePath() : qtFileDialog->selectedFiles().value(0));
669 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc]
670 initWithAcceptMode:qtFileDialog->acceptMode()
671 title:qtFileDialog->windowTitle()
672 hideNameFilterDetails:qtFileDialog->testOption(QFileDialog::HideNameFilterDetails)
673 qDirFilter:qtFileDialog->filter()
674 fileOptions:qtFileDialog->options()
675 fileMode:qtFileDialog->fileMode()
677 confirmOverwrite:!qtFileDialog->testOption(QFileDialog::DontConfirmOverwrite)
678 fileDialog:qtFileDialog
681 mDelegate = delegate;
684 bool QCocoaFileDialogHelper::showCocoaFilePanel()
687 createNSOpenSavePanelDelegate();
688 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
689 if (qt_mac_is_macsheet(qtFileDialog))
690 [delegate showWindowModalSheet:qtFileDialog->parentWidget()];
692 [delegate showModelessPanel];
696 bool QCocoaFileDialogHelper::hideCocoaFilePanel()
699 // Nothing to do. We return false to leave the question
700 // open regarding whether or not to go native:
703 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
704 [delegate closePanel];
705 // Even when we hide it, we are still using a
706 // native dialog, so return true:
711 void QCocoaFileDialogHelper::platformNativeDialogModalHelp()
713 // Do a queued meta-call to open the native modal dialog so it opens after the new
714 // event loop has started to execute (in QDialog::exec). Using a timer rather than
715 // a queued meta call is intentional to ensure that the call is only delivered when
716 // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
717 // running (which is the case if e.g a top-most QEventLoop has been
718 // interrupted, and the second-most event loop has not yet been reactivated (regardless
719 // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
720 QTimer::singleShot(1, qtFileDialog, SLOT(_q_platformRunNativeAppModalPanel()));
723 void QCocoaFileDialogHelper::_q_platformRunNativeAppModalPanel()
727 QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
729 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
730 [delegate runApplicationModalPanel];
731 if (dialogResultCode_sys() == QPlatformDialogHelper::Accepted)
732 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "accept");
734 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "reject");
737 QPlatformDialogHelper::DialogCode QCocoaFileDialogHelper::dialogResultCode_sys()
739 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
740 return [delegate dialogResultCode];
743 bool QCocoaFileDialogHelper::defaultNameFilterDisables() const
750 #endif // QT_NO_FILEDIALOG