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 QFileDialogPrivate *mPriv;
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 priv:(QFileDialogPrivate *)priv
137 helper:(QCocoaFileDialogHelper *)helper
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;
159 mLastFilterCheckPath = new QString;
160 mQDirFilterEntryList = new QStringList;
161 mNameFilterDropDownList = new QStringList(priv->nameFilters);
162 QString selectedVisualNameFilter = priv->qFileDialogUi->fileTypeCombo->currentText();
163 mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
165 QFileInfo sel(selectFile);
167 mCurrentDir = [qt_mac_QStringToNSString(sel.absoluteFilePath()) retain];
168 mCurrentSelection = new QString;
170 mCurrentDir = [qt_mac_QStringToNSString(sel.absolutePath()) retain];
171 mCurrentSelection = new QString(sel.absoluteFilePath());
174 [mSavePanel setTitle:qt_mac_QStringToNSString(title)];
175 [self createPopUpButton:selectedVisualNameFilter hideDetails:hideNameFilterDetails];
176 [self createTextField];
177 [self createAccessory];
178 [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
181 [mSavePanel setPrompt:[self strip:mPriv->acceptLabel]];
182 if (mPriv->fileNameLabelExplicitlySat)
183 [mSavePanel setNameFieldLabel:[self strip:mPriv->qFileDialogUi->fileNameLabel->text()]];
186 [self updateProperties];
195 delete mLastFilterCheckPath;
196 delete mQDirFilterEntryList;
197 delete mNameFilterDropDownList;
198 delete mSelectedNameFilter;
199 delete mCurrentSelection;
201 [mSavePanel orderOut:mSavePanel];
202 [mSavePanel setAccessoryView:nil];
203 [mPopUpButton release];
204 [mTextField release];
205 [mAccessoryView release];
206 [mSavePanel setDelegate:nil];
207 [mSavePanel release];
208 [mCurrentDir release];
212 - (NSString *)strip:(const QString &)label
215 return qt_mac_QStringToNSString(a.iconText());
220 *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
224 - (void)showModelessPanel
227 QFileInfo info(*mCurrentSelection);
228 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
229 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
230 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
231 || [self panel:nil shouldShowFilename:filepath];
233 beginForDirectory:mCurrentDir
234 file:selectable ? filename : nil
236 modelessDelegate:self
237 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
242 - (BOOL)runApplicationModalPanel
244 QFileInfo info(*mCurrentSelection);
245 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
246 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
247 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
248 || [self panel:nil shouldShowFilename:filepath];
249 mReturnCode = [mSavePanel
250 runModalForDirectory:mCurrentDir
251 file:selectable ? filename : @"untitled"];
253 QAbstractEventDispatcher::instance()->interrupt();
254 return (mReturnCode == NSOKButton);
257 - (QT_PREPEND_NAMESPACE(QDialog::DialogCode))dialogResultCode
259 return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QDialog::Accepted) : QT_PREPEND_NAMESPACE(QDialog::Rejected);
262 - (void)showWindowModalSheet:(QWidget *)docWidget
265 QFileInfo info(*mCurrentSelection);
266 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
267 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
268 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
269 || [self panel:nil shouldShowFilename:filepath];
271 beginSheetForDirectory:mCurrentDir
272 file:selectable ? filename : nil
275 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
279 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
283 if ([filename length] == 0)
286 // Always accept directories regardless of their names (unless it is a bundle):
288 if ([[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir] && isDir) {
289 if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
290 if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
295 QString qtFileName = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename);
296 QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C)));
297 QString path = info.absolutePath();
298 if (path != *mLastFilterCheckPath){
299 *mLastFilterCheckPath = path;
300 *mQDirFilterEntryList = info.dir().entryList(*mQDirFilter);
302 // Check if the QDir filter accepts the file:
303 if (!mQDirFilterEntryList->contains(info.fileName()))
306 // No filter means accept everything
307 if (mSelectedNameFilter->isEmpty())
309 // Check if the current file name filter accepts the file:
310 for (int i=0; i<mSelectedNameFilter->size(); ++i) {
311 if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
317 - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
322 if (mConfirmOverwrite)
325 // User has clicked save, and no overwrite confirmation should occur.
326 // To get the latter, we need to change the name we return (hence the prefix):
327 return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
330 - (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
332 [mPopUpButton removeAllItems];
333 *mNameFilterDropDownList = filters;
334 if (filters.size() > 0){
335 for (int i=0; i<filters.size(); ++i) {
336 QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
337 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
339 [mPopUpButton selectItemAtIndex:0];
340 [mSavePanel setAccessoryView:mAccessoryView];
342 [mSavePanel setAccessoryView:nil];
344 [self filterChanged:self];
347 - (void)filterChanged:(id)sender
349 // This mDelegate function is called when the _name_ filter changes.
351 QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
352 *mSelectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
353 [mSavePanel validateVisibleColumns];
354 [self updateProperties];
356 mHelper->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
359 - (QString)currentNameFilter
361 return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
364 - (QStringList)selectedFiles
367 return QT_PREPEND_NAMESPACE(qt_mac_NSArrayToQStringList)([mOpenPanel filenames]);
370 QString filename = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
371 result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_"));
376 - (void)updateProperties
378 // Call this functions if mFileMode, mFileOptions,
379 // mNameFilterDropDownList or mQDirFilter changes.
380 // The savepanel does not contain the neccessary functions for this.
381 bool chooseFilesOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFile)
382 || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles);
383 bool chooseDirsOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::Directory)
384 || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::DirectoryOnly)
385 || *mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ShowDirsOnly);
387 [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
388 [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
389 [mSavePanel setCanCreateDirectories:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ReadOnly))];
390 [mOpenPanel setAllowsMultipleSelection:(mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles))];
391 [mOpenPanel setResolvesAliases:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::DontResolveSymlinks))];
393 QStringList ext = [self acceptableExtensionsForSave];
394 if (mPriv && !ext.isEmpty() && !mPriv->defaultSuffix.isEmpty())
395 ext.prepend(mPriv->defaultSuffix);
396 [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))];
398 if ([mSavePanel isVisible])
399 [mOpenPanel validateVisibleColumns];
402 - (void)panelSelectionDidChange:(id)sender
406 QString selection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString([mSavePanel filename]));
407 if (selection != mCurrentSelection) {
408 *mCurrentSelection = selection;
409 mHelper->QNSOpenSavePanelDelegate_selectionChanged(selection);
414 - (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
417 Q_UNUSED(contextInfo);
418 mReturnCode = returnCode;
420 mHelper->QNSOpenSavePanelDelegate_panelClosed(returnCode == NSOKButton);
423 - (void)panel:(id)sender directoryDidChange:(NSString *)path
428 if ([path isEqualToString:mCurrentDir])
431 [mCurrentDir release];
432 mCurrentDir = [path retain];
433 mHelper->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString(mCurrentDir)));
437 Returns a list of extensions (e.g. "png", "jpg", "gif")
438 for the current name filter. If a filter do not conform
439 to the format *.xyz or * or *.*, an empty list
440 is returned meaning accept everything.
442 - (QStringList)acceptableExtensionsForSave
445 for (int i=0; i<mSelectedNameFilter->count(); ++i) {
446 const QString &filter = mSelectedNameFilter->at(i);
447 if (filter.startsWith(QLatin1String("*."))
448 && !filter.contains(QLatin1Char('?'))
449 && filter.count(QLatin1Char('*')) == 1) {
450 result += filter.mid(2);
452 return QStringList(); // Accept everything
458 - (QString)removeExtensions:(const QString &)filter
460 QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(QFileDialogPrivate::qt_file_dialog_filter_reg_exp)));
461 if (regExp.indexIn(filter) != -1)
462 return regExp.cap(1).trimmed();
466 - (void)createTextField
468 NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
469 mTextField = [[NSTextField alloc] initWithFrame:textRect];
470 [[mTextField cell] setFont:[NSFont systemFontOfSize:
471 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
472 [mTextField setAlignment:NSRightTextAlignment];
473 [mTextField setEditable:false];
474 [mTextField setSelectable:false];
475 [mTextField setBordered:false];
476 [mTextField setDrawsBackground:false];
478 [mTextField setStringValue:[self strip:mPriv->qFileDialogUi->fileTypeLabel->text()]];
480 [mTextField setStringValue:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(QT_PREPEND_NAMESPACE(QFileDialog::tr)("Files of type:"))];
483 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
485 NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
486 mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
487 [mPopUpButton setTarget:self];
488 [mPopUpButton setAction:@selector(filterChanged:)];
490 QStringList *filters = mNameFilterDropDownList;
491 if (filters->size() > 0){
492 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
493 QString filter = hideDetails ? [self removeExtensions:filters->at(i)] : filters->at(i);
494 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
495 if (filters->at(i).startsWith(selectedFilter))
496 [mPopUpButton selectItemAtIndex:i];
501 - (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
503 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
504 if (mNameFilterDropDownList->at(i).startsWith(name))
505 return QFileDialogPrivate::qt_clean_filter_list(mNameFilterDropDownList->at(i));
507 return QStringList();
510 - (void)createAccessory
512 NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
513 mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
514 [mAccessoryView addSubview:mTextField];
515 [mAccessoryView addSubview:mPopUpButton];
522 static bool qt_mac_is_macsheet(const QWidget *w)
527 Qt::WindowModality modality = w->windowModality();
528 if (modality == Qt::ApplicationModal)
530 return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet);
533 QCocoaFileDialogHelper::QCocoaFileDialogHelper(QFileDialog *dialog) :
534 qtFileDialog(dialog), mDelegate(0)
538 QCocoaFileDialogHelper::~QCocoaFileDialogHelper()
543 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
545 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "currentChanged", Q_ARG(QString, newPath));
548 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
551 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "accept");
553 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "reject");
556 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
558 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
559 priv->setLastVisitedDirectory(newDir);
560 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "directoryEntered", Q_ARG(QString, newDir));
563 void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
565 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
566 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "filterSelected", Q_ARG(QString, priv->nameFilters.at(menuIndex)));
569 extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp
570 extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp
572 void QCocoaFileDialogHelper::setDirectory_sys(const QString &directory)
574 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
575 [delegate->mSavePanel setDirectory:qt_mac_QStringToNSString(directory)];
578 QString QCocoaFileDialogHelper::directory_sys() const
580 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
581 return qt_mac_NSStringToQString([delegate->mSavePanel directory]);
584 void QCocoaFileDialogHelper::selectFile_sys(const QString &filename)
586 QString filePath = filename;
587 if (QDir::isRelativePath(filePath))
588 filePath = QFileInfo(directory_sys(), filePath).filePath();
590 // There seems to no way to select a file once the dialog is running.
591 // So do the next best thing, set the file's directory:
592 setDirectory_sys(QFileInfo(filePath).absolutePath());
595 QStringList QCocoaFileDialogHelper::selectedFiles_sys() const
597 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
598 return [delegate selectedFiles];
601 void QCocoaFileDialogHelper::setNameFilters_sys(const QStringList &filters)
603 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
604 bool hideDetails = qtFileDialog->testOption(QFileDialog::HideNameFilterDetails);
605 [delegate setNameFilters:filters hideDetails:hideDetails];
608 void QCocoaFileDialogHelper::setFilter_sys()
610 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
611 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
612 *(delegate->mQDirFilter) = priv->model->filter();
613 delegate->mFileMode = priv->fileMode;
614 [delegate->mSavePanel setTitle:qt_mac_QStringToNSString(qtFileDialog->windowTitle())];
615 [delegate->mSavePanel setPrompt:[delegate strip:priv->acceptLabel]];
616 if (priv->fileNameLabelExplicitlySat)
617 [delegate->mSavePanel setNameFieldLabel:[delegate strip:priv->qFileDialogUi->fileNameLabel->text()]];
619 [delegate updateProperties];
622 void QCocoaFileDialogHelper::selectNameFilter_sys(const QString &filter)
624 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
625 int index = priv->nameFilters.indexOf(filter);
627 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
628 [delegate->mPopUpButton selectItemAtIndex:index];
629 [delegate filterChanged:nil];
633 QString QCocoaFileDialogHelper::selectedNameFilter_sys() const
635 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
636 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
637 int index = [delegate->mPopUpButton indexOfSelectedItem];
638 return index != -1 ? priv->nameFilters.at(index) : QString();
641 void QCocoaFileDialogHelper::deleteNativeDialog_sys()
643 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
644 [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release];
646 priv->nativeDialogInUse = false;
649 bool QCocoaFileDialogHelper::setVisible_sys(bool visible)
652 if (!visible == qtFileDialog->isHidden())
655 if (qtFileDialog->windowFlags() & Qt::WindowStaysOnTopHint) {
656 // The native file dialog tries all it can to stay
657 // on the NSModalPanel level. And it might also show
658 // its own "create directory" dialog that we cannot control.
659 // So we need to use the non-native version in this case...
663 return visible ? showCocoaFilePanel() : hideCocoaFilePanel();
666 void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate()
668 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
672 bool selectDir = qtFileDialog->selectedFiles().isEmpty();
673 QString selection(selectDir ? qtFileDialog->directory().absolutePath() : qtFileDialog->selectedFiles().value(0));
674 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc]
675 initWithAcceptMode:priv->acceptMode
676 title:qtFileDialog->windowTitle()
677 hideNameFilterDetails:qtFileDialog->testOption(QFileDialog::HideNameFilterDetails)
678 qDirFilter:priv->model->filter()
679 fileOptions:priv->opts
680 fileMode:priv->fileMode
682 confirmOverwrite:!qtFileDialog->testOption(QFileDialog::DontConfirmOverwrite)
686 mDelegate = delegate;
689 bool QCocoaFileDialogHelper::showCocoaFilePanel()
692 createNSOpenSavePanelDelegate();
693 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
694 if (qt_mac_is_macsheet(qtFileDialog))
695 [delegate showWindowModalSheet:qtFileDialog->parentWidget()];
697 [delegate showModelessPanel];
701 bool QCocoaFileDialogHelper::hideCocoaFilePanel()
704 // Nothing to do. We return false to leave the question
705 // open regarding whether or not to go native:
708 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
709 [delegate closePanel];
710 // Even when we hide it, we are still using a
711 // native dialog, so return true:
716 void QCocoaFileDialogHelper::platformNativeDialogModalHelp()
718 // Do a queued meta-call to open the native modal dialog so it opens after the new
719 // event loop has started to execute (in QDialog::exec). Using a timer rather than
720 // a queued meta call is intentional to ensure that the call is only delivered when
721 // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
722 // running (which is the case if e.g a top-most QEventLoop has been
723 // interrupted, and the second-most event loop has not yet been reactivated (regardless
724 // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
725 QFileDialogPrivate *priv = static_cast<QFileDialogPrivate*>(d_ptr);
726 if (priv->nativeDialogInUse){
727 QTimer::singleShot(1, qtFileDialog, SLOT(_q_platformRunNativeAppModalPanel()));
731 void QCocoaFileDialogHelper::_q_platformRunNativeAppModalPanel()
735 QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
737 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
738 [delegate runApplicationModalPanel];
739 if (dialogResultCode_sys() == QDialog::Accepted)
740 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "accept");
742 qtFileDialog->metaObject()->invokeMethod(qtFileDialog, "reject");
745 QDialog::DialogCode QCocoaFileDialogHelper::dialogResultCode_sys()
747 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
748 return [delegate dialogResultCode];
751 bool QCocoaFileDialogHelper::defaultNameFilterDisables() const
758 #endif // QT_NO_FILEDIALOG