src/gui/dialogs/qfiledialog_mac.mm
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qfiledialog.h"
       
    43 
       
    44 #ifndef QT_NO_FILEDIALOG
       
    45 
       
    46 /*****************************************************************************
       
    47   QFileDialog debug facilities
       
    48  *****************************************************************************/
       
    49 //#define DEBUG_FILEDIALOG_FILTERS
       
    50 
       
    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>
       
    56 #include <qregexp.h>
       
    57 #include <qbuffer.h>
       
    58 #include <qdebug.h>
       
    59 #include <qstringlist.h>
       
    60 #include <qaction.h>
       
    61 #include <qtextcodec.h>
       
    62 #include <qvarlengtharray.h>
       
    63 #include <qdesktopwidget.h>
       
    64 #include <stdlib.h>
       
    65 #include <qabstracteventdispatcher.h>
       
    66 #include "ui_qfiledialog.h"
       
    67 
       
    68 QT_BEGIN_NAMESPACE
       
    69 
       
    70 extern QStringList qt_make_filter_list(const QString &filter); // qfiledialog.cpp
       
    71 extern QStringList qt_clean_filter_list(const QString &filter); // qfiledialog.cpp
       
    72 extern const char *qt_file_dialog_filter_reg_exp; // qfiledialog.cpp
       
    73 extern bool qt_mac_is_macsheet(const QWidget *w); // qwidget_mac.mm
       
    74 
       
    75 QT_END_NAMESPACE
       
    76 
       
    77 QT_FORWARD_DECLARE_CLASS(QFileDialogPrivate)
       
    78 QT_FORWARD_DECLARE_CLASS(QString)
       
    79 QT_FORWARD_DECLARE_CLASS(QStringList)
       
    80 QT_FORWARD_DECLARE_CLASS(QWidget)
       
    81 QT_FORWARD_DECLARE_CLASS(QAction)
       
    82 QT_FORWARD_DECLARE_CLASS(QFileInfo)
       
    83 QT_USE_NAMESPACE
       
    84 
       
    85 @class QNSOpenSavePanelDelegate;
       
    86 
       
    87 @interface QNSOpenSavePanelDelegate : NSObject {
       
    88     @public
       
    89     NSOpenPanel *mOpenPanel;
       
    90     NSSavePanel *mSavePanel;
       
    91     NSView *mAccessoryView;
       
    92     NSPopUpButton *mPopUpButton;
       
    93     NSTextField *mTextField;
       
    94     QFileDialogPrivate *mPriv;
       
    95     NSString *mCurrentDir;
       
    96     bool mConfirmOverwrite;
       
    97     int mReturnCode;
       
    98 
       
    99     QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode) mAcceptMode;
       
   100     QT_PREPEND_NAMESPACE(QDir::Filters) *mQDirFilter;
       
   101     QT_PREPEND_NAMESPACE(QFileDialog::FileMode) mFileMode;
       
   102     QT_PREPEND_NAMESPACE(QFileDialog::Options) *mFileOptions;
       
   103 
       
   104     QString *mLastFilterCheckPath;
       
   105     QString *mCurrentSelection;
       
   106     QStringList *mQDirFilterEntryList;
       
   107     QStringList *mNameFilterDropDownList;
       
   108     QStringList *mSelectedNameFilter;
       
   109 }
       
   110 
       
   111 - (NSString *)strip:(const QString &)label;
       
   112 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
       
   113 - (void)filterChanged:(id)sender;
       
   114 - (void)showModelessPanel;
       
   115 - (BOOL)runApplicationModalPanel;
       
   116 - (void)showWindowModalSheet:(QWidget *)docWidget;
       
   117 - (void)updateProperties;
       
   118 - (QStringList)acceptableExtensionsForSave;
       
   119 - (QString)removeExtensions:(const QString &)filter;
       
   120 - (void)createTextField;
       
   121 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails;
       
   122 - (void)createAccessory;
       
   123 
       
   124 @end
       
   125 
       
   126 @implementation QNSOpenSavePanelDelegate
       
   127 
       
   128 - (id)initWithAcceptMode:(QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode))acceptMode
       
   129     title:(const QString &)title
       
   130     nameFilters:(const QStringList &)nameFilters
       
   131     selectedNameFilter:(const QString &)selectedNameFilter
       
   132     hideNameFilterDetails:(bool)hideNameFilterDetails
       
   133     qDirFilter:(QT_PREPEND_NAMESPACE(QDir::Filters))qDirFilter
       
   134     fileOptions:(QT_PREPEND_NAMESPACE(QFileDialog::Options))fileOptions
       
   135     fileMode:(QT_PREPEND_NAMESPACE(QFileDialog::FileMode))fileMode
       
   136     selectFile:(const QString &)selectFile
       
   137     confirmOverwrite:(bool)confirm
       
   138     priv:(QFileDialogPrivate *)priv
       
   139 {
       
   140     self = [super init];
       
   141 
       
   142     mAcceptMode = acceptMode;
       
   143     if (mAcceptMode == QT_PREPEND_NAMESPACE(QFileDialog::AcceptOpen)){
       
   144         mOpenPanel = [NSOpenPanel openPanel];
       
   145         mSavePanel = mOpenPanel;
       
   146     } else {
       
   147         mSavePanel = [NSSavePanel savePanel];
       
   148         mOpenPanel = 0;
       
   149     }
       
   150 
       
   151     [mSavePanel setLevel:NSModalPanelWindowLevel];
       
   152     [mSavePanel setDelegate:self];
       
   153     mQDirFilter = new QT_PREPEND_NAMESPACE(QDir::Filters)(qDirFilter);
       
   154     mFileOptions = new QT_PREPEND_NAMESPACE(QFileDialog::Options)(fileOptions);
       
   155     mFileMode = fileMode;
       
   156     mConfirmOverwrite = confirm;
       
   157     mReturnCode = -1;
       
   158     mPriv = priv;
       
   159     mLastFilterCheckPath = new QString;
       
   160     mQDirFilterEntryList = new QStringList;
       
   161     mNameFilterDropDownList = new QStringList(nameFilters);
       
   162     mSelectedNameFilter = new QStringList(qt_clean_filter_list(selectedNameFilter));
       
   163     QFileInfo sel(selectFile);
       
   164     if (sel.isDir()){
       
   165         mCurrentDir = [qt_mac_QStringToNSString(sel.absoluteFilePath()) retain];
       
   166         mCurrentSelection = new QString;
       
   167     } else {
       
   168         mCurrentDir = [qt_mac_QStringToNSString(sel.absolutePath()) retain];
       
   169         mCurrentSelection = new QString(sel.absoluteFilePath());
       
   170     }
       
   171     [mSavePanel setTitle:qt_mac_QStringToNSString(title)];
       
   172     [self createPopUpButton:selectedNameFilter hideDetails:hideNameFilterDetails];
       
   173     [self createTextField];
       
   174     [self createAccessory];
       
   175     [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
       
   176 
       
   177     if (mPriv){
       
   178         [mSavePanel setPrompt:[self strip:mPriv->acceptLabel]];
       
   179         if (mPriv->fileNameLabelExplicitlySat)
       
   180             [mSavePanel setNameFieldLabel:[self strip:mPriv->qFileDialogUi->fileNameLabel->text()]];
       
   181     }
       
   182 
       
   183     [self updateProperties];
       
   184     [mSavePanel retain];
       
   185     return self;
       
   186 }
       
   187 
       
   188 - (void)dealloc
       
   189 {
       
   190     delete mQDirFilter;
       
   191     delete mFileOptions;
       
   192     delete mLastFilterCheckPath;
       
   193     delete mQDirFilterEntryList;
       
   194     delete mNameFilterDropDownList;
       
   195     delete mSelectedNameFilter;
       
   196     delete mCurrentSelection;
       
   197 
       
   198     [mSavePanel orderOut:mSavePanel];
       
   199     [mSavePanel setAccessoryView:nil];
       
   200     [mPopUpButton release];
       
   201     [mTextField release];
       
   202     [mAccessoryView release];
       
   203     [mSavePanel setDelegate:nil];
       
   204     [mSavePanel release];
       
   205     [mCurrentDir release];
       
   206     [super dealloc];
       
   207 }
       
   208 
       
   209 - (NSString *)strip:(const QString &)label
       
   210 {
       
   211     QAction a(label, 0);
       
   212     return qt_mac_QStringToNSString(a.iconText());
       
   213 }
       
   214 
       
   215 - (void)closePanel
       
   216 {
       
   217     *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
       
   218     [mSavePanel close];
       
   219 }
       
   220 
       
   221 - (void)showModelessPanel
       
   222 {
       
   223     if (mOpenPanel){
       
   224         QFileInfo info(*mCurrentSelection);
       
   225         NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
       
   226         NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
       
   227         bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
       
   228             || [self panel:nil shouldShowFilename:filepath];
       
   229         [mOpenPanel 
       
   230             beginForDirectory:mCurrentDir
       
   231             file:selectable ? filename : nil
       
   232             types:nil
       
   233             modelessDelegate:self
       
   234             didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
       
   235             contextInfo:nil];
       
   236     }
       
   237 }
       
   238 
       
   239 - (BOOL)runApplicationModalPanel
       
   240 {
       
   241     QFileInfo info(*mCurrentSelection);
       
   242     NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
       
   243     NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
       
   244     bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
       
   245         || [self panel:nil shouldShowFilename:filepath];
       
   246     mReturnCode = [mSavePanel 
       
   247         runModalForDirectory:mCurrentDir
       
   248         file:selectable ? filename : @"untitled"];
       
   249 
       
   250     QAbstractEventDispatcher::instance()->interrupt();
       
   251     return (mReturnCode == NSOKButton);
       
   252 }
       
   253 
       
   254 - (QT_PREPEND_NAMESPACE(QDialog::DialogCode))dialogResultCode
       
   255 {
       
   256     return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QDialog::Accepted) : QT_PREPEND_NAMESPACE(QDialog::Rejected);
       
   257 }
       
   258 
       
   259 - (void)showWindowModalSheet:(QWidget *)docWidget
       
   260 {
       
   261     Q_UNUSED(docWidget);
       
   262     QFileInfo info(*mCurrentSelection);
       
   263     NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
       
   264     NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
       
   265     bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
       
   266         || [self panel:nil shouldShowFilename:filepath];
       
   267     [mSavePanel 
       
   268         beginSheetForDirectory:mCurrentDir
       
   269         file:selectable ? filename : nil
       
   270 #ifdef QT_MAC_USE_COCOA
       
   271         modalForWindow:QT_PREPEND_NAMESPACE(qt_mac_window_for)(docWidget)
       
   272 #else
       
   273         modalForWindow:nil
       
   274 #endif
       
   275         modalDelegate:self
       
   276         didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
       
   277         contextInfo:nil];
       
   278 }
       
   279 
       
   280 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
       
   281 {
       
   282     Q_UNUSED(sender);
       
   283 
       
   284     if ([filename length] == 0)
       
   285         return NO;
       
   286 
       
   287     QString qtFileName = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename);
       
   288     QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C)));
       
   289     QString path = info.absolutePath();
       
   290     if (path != *mLastFilterCheckPath){
       
   291         *mLastFilterCheckPath = path;
       
   292         *mQDirFilterEntryList = info.dir().entryList(*mQDirFilter);
       
   293     }
       
   294     // Check if the QDir filter accepts the file:
       
   295     if (!mQDirFilterEntryList->contains(info.fileName()))
       
   296         return NO;
       
   297 
       
   298     // Always accept directories regardless of their names:
       
   299     BOOL isDir;
       
   300     if ([[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir] && isDir)
       
   301         return YES;
       
   302 
       
   303     // No filter means accept everything
       
   304     if (mSelectedNameFilter->isEmpty())
       
   305         return YES;
       
   306     // Check if the current file name filter accepts the file:
       
   307     for (int i=0; i<mSelectedNameFilter->size(); ++i) {
       
   308         if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
       
   309             return YES;
       
   310     }
       
   311     return NO;
       
   312 }
       
   313 
       
   314 - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
       
   315 {
       
   316     Q_UNUSED(sender);
       
   317     if (!okFlag)
       
   318         return filename;
       
   319     if (mConfirmOverwrite)
       
   320         return filename;
       
   321 
       
   322     // User has clicked save, and no overwrite confirmation should occur.
       
   323     // To get the latter, we need to change the name we return (hence the prefix):
       
   324     return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
       
   325 }
       
   326 
       
   327 - (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
       
   328 {
       
   329     [mPopUpButton removeAllItems];
       
   330     *mNameFilterDropDownList = filters;
       
   331     if (filters.size() > 0){
       
   332         for (int i=0; i<filters.size(); ++i) {
       
   333             QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
       
   334             [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
       
   335         }
       
   336         [mPopUpButton selectItemAtIndex:0];
       
   337         [mSavePanel setAccessoryView:mAccessoryView];
       
   338     } else
       
   339         [mSavePanel setAccessoryView:nil];
       
   340 
       
   341     [self filterChanged:self];
       
   342 }
       
   343 
       
   344 - (void)filterChanged:(id)sender
       
   345 {
       
   346     // This mDelegate function is called when the _name_ filter changes.
       
   347     Q_UNUSED(sender);
       
   348     QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
       
   349     *mSelectedNameFilter = QT_PREPEND_NAMESPACE(qt_clean_filter_list)(selection);
       
   350     [mSavePanel validateVisibleColumns];
       
   351     [self updateProperties];
       
   352     if (mPriv)
       
   353         mPriv->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
       
   354 }
       
   355 
       
   356 - (QString)currentNameFilter
       
   357 {
       
   358     return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
       
   359 }
       
   360 
       
   361 - (QStringList)selectedFiles
       
   362 {
       
   363     if (mOpenPanel)
       
   364         return QT_PREPEND_NAMESPACE(qt_mac_NSArrayToQStringList)([mOpenPanel filenames]);
       
   365     else{
       
   366         QStringList result;
       
   367         QString filename = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
       
   368         result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_"));
       
   369         return result;
       
   370     }
       
   371 }
       
   372 
       
   373 - (void)updateProperties
       
   374 {
       
   375     // Call this functions if mFileMode, mFileOptions,
       
   376     // mNameFilterDropDownList or mQDirFilter changes.
       
   377     // The savepanel does not contain the neccessary functions for this.
       
   378     bool chooseFilesOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFile)
       
   379         || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles);
       
   380     bool chooseDirsOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::Directory)
       
   381         || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::DirectoryOnly)
       
   382         || *mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ShowDirsOnly);
       
   383 
       
   384     [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
       
   385     [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
       
   386     [mSavePanel setCanCreateDirectories:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ReadOnly))];
       
   387     [mOpenPanel setAllowsMultipleSelection:(mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles))];
       
   388     [mOpenPanel setResolvesAliases:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::DontResolveSymlinks))];
       
   389 
       
   390     QStringList ext = [self acceptableExtensionsForSave];
       
   391     if (mPriv && !ext.isEmpty() && !mPriv->defaultSuffix.isEmpty())
       
   392         ext.prepend(mPriv->defaultSuffix);
       
   393     [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))];
       
   394 
       
   395     if ([mSavePanel isVisible])
       
   396         [mOpenPanel validateVisibleColumns];
       
   397 }
       
   398 
       
   399 - (void)panelSelectionDidChange:(id)sender
       
   400 {
       
   401     Q_UNUSED(sender);
       
   402     *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString([mSavePanel filename]));
       
   403     if (mPriv)
       
   404         mPriv->QNSOpenSavePanelDelegate_selectionChanged(*mCurrentSelection);
       
   405 }
       
   406 
       
   407 - (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode  contextInfo:(void *)contextInfo
       
   408 {
       
   409     Q_UNUSED(panel);
       
   410     Q_UNUSED(contextInfo);
       
   411     mReturnCode = returnCode;
       
   412     if (mPriv)
       
   413         mPriv->QNSOpenSavePanelDelegate_panelClosed(returnCode == NSOKButton);
       
   414 }
       
   415 
       
   416 - (void)panel:(id)sender directoryDidChange:(NSString *)path
       
   417 {
       
   418     Q_UNUSED(sender);
       
   419     if (!mPriv)
       
   420         return;
       
   421     if ([path isEqualToString:mCurrentDir])
       
   422         return;
       
   423 
       
   424     [mCurrentDir release];
       
   425     mCurrentDir = [path retain];
       
   426     mPriv->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString(mCurrentDir)));
       
   427 }
       
   428 
       
   429 /*
       
   430     Returns a list of extensions (e.g. "png", "jpg", "gif")
       
   431     for the current name filter. If a filter do not conform
       
   432     to the format *.xyz or * or *.*, an empty list
       
   433     is returned meaning accept everything.
       
   434 */
       
   435 - (QStringList)acceptableExtensionsForSave
       
   436 {
       
   437     QStringList result;
       
   438     for (int i=0; i<mSelectedNameFilter->count(); ++i) {
       
   439         const QString &filter = mSelectedNameFilter->at(i);
       
   440         if (filter.startsWith(QLatin1String("*."))
       
   441                 && !filter.contains(QLatin1Char('?'))
       
   442                 && filter.count(QLatin1Char('*')) == 1) {
       
   443             result += filter.mid(2);
       
   444         } else {
       
   445             return QStringList(); // Accept everything
       
   446         }
       
   447     }
       
   448     return result;
       
   449 }
       
   450 
       
   451 - (QString)removeExtensions:(const QString &)filter
       
   452 {
       
   453     QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(qt_file_dialog_filter_reg_exp)));
       
   454     if (regExp.indexIn(filter) != -1)
       
   455         return regExp.cap(1).trimmed();
       
   456     return filter;
       
   457 }
       
   458 
       
   459 - (void)createTextField
       
   460 {
       
   461     NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
       
   462     mTextField = [[NSTextField alloc] initWithFrame:textRect];
       
   463     [[mTextField cell] setFont:[NSFont systemFontOfSize:
       
   464             [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
       
   465     [mTextField setAlignment:NSRightTextAlignment];
       
   466     [mTextField setEditable:false];
       
   467     [mTextField setSelectable:false];
       
   468     [mTextField setBordered:false];
       
   469     [mTextField setDrawsBackground:false];
       
   470     if (mPriv){
       
   471         [mTextField setStringValue:[self strip:mPriv->qFileDialogUi->fileTypeLabel->text()]];
       
   472     } else
       
   473         [mTextField setStringValue:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(QT_PREPEND_NAMESPACE(QFileDialog::tr)("Files of type:"))];
       
   474 }
       
   475 
       
   476 - (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
       
   477 {
       
   478     NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
       
   479     mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
       
   480     [mPopUpButton setTarget:self];
       
   481     [mPopUpButton setAction:@selector(filterChanged:)];
       
   482 
       
   483     QStringList *filters = mNameFilterDropDownList;
       
   484     if (filters->size() > 0){
       
   485         for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
       
   486             QString filter = hideDetails ? [self removeExtensions:filters->at(i)] : filters->at(i);
       
   487             [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
       
   488             if (filters->at(i) == selectedFilter)
       
   489                 [mPopUpButton selectItemAtIndex:i];
       
   490         }
       
   491     }
       
   492 }
       
   493 
       
   494 - (void)createAccessory
       
   495 {
       
   496     NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
       
   497     mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
       
   498     [mAccessoryView addSubview:mTextField];
       
   499     [mAccessoryView addSubview:mPopUpButton];
       
   500 }
       
   501 
       
   502 @end
       
   503 
       
   504 QT_BEGIN_NAMESPACE
       
   505 
       
   506 void QFileDialogPrivate::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
       
   507 {
       
   508     emit q_func()->currentChanged(newPath);
       
   509 }
       
   510 
       
   511 void QFileDialogPrivate::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
       
   512 {
       
   513     if (accepted)
       
   514         q_func()->accept();
       
   515     else
       
   516         q_func()->reject();
       
   517 }
       
   518 
       
   519 void QFileDialogPrivate::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
       
   520 {
       
   521     setLastVisitedDirectory(newDir);
       
   522     emit q_func()->directoryEntered(newDir);
       
   523 }
       
   524 
       
   525 void QFileDialogPrivate::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
       
   526 {
       
   527     emit q_func()->filterSelected(nameFilters.at(menuIndex));
       
   528 }
       
   529 
       
   530 extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp
       
   531 extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp
       
   532 
       
   533 void QFileDialogPrivate::setDirectory_sys(const QString &directory)
       
   534 {
       
   535 #ifndef QT_MAC_USE_COCOA
       
   536     if (directory == mCurrentLocation)
       
   537         return;
       
   538     mCurrentLocation = directory;
       
   539     emit q_func()->directoryEntered(mCurrentLocation);
       
   540 
       
   541     FSRef fsRef;
       
   542     if (qt_mac_create_fsref(directory, &fsRef) == noErr) {
       
   543         AEDesc desc;
       
   544         if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr)
       
   545             NavCustomControl(mDialog, kNavCtlSetLocation, (void*)&desc);
       
   546     }
       
   547 #else
       
   548     QMacCocoaAutoReleasePool pool;
       
   549     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   550     [delegate->mSavePanel setDirectory:qt_mac_QStringToNSString(directory)];
       
   551 #endif
       
   552 }
       
   553 
       
   554 QString QFileDialogPrivate::directory_sys() const
       
   555 {
       
   556 #ifndef QT_MAC_USE_COCOA
       
   557     return mCurrentLocation;
       
   558 #else
       
   559     QMacCocoaAutoReleasePool pool;
       
   560     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   561     return qt_mac_NSStringToQString([delegate->mSavePanel directory]);
       
   562 #endif
       
   563 }
       
   564 
       
   565 void QFileDialogPrivate::selectFile_sys(const QString &filename)
       
   566 {
       
   567     QString filePath = filename;
       
   568     if (QDir::isRelativePath(filePath))
       
   569         filePath = QFileInfo(directory_sys(), filePath).filePath();
       
   570 
       
   571 #ifndef QT_MAC_USE_COCOA
       
   572     // Update the selection list immidiatly, so
       
   573     // subsequent calls to selectedFiles() gets correct:
       
   574     mCurrentSelectionList.clear();
       
   575     mCurrentSelectionList << filename;
       
   576     if (mCurrentSelection != filename){
       
   577         mCurrentSelection = filename;
       
   578         emit q_func()->currentChanged(mCurrentSelection);
       
   579     }
       
   580 
       
   581     AEDescList descList;
       
   582     if (AECreateList(0, 0, false, &descList) != noErr)
       
   583         return;
       
   584 
       
   585     FSRef fsRef;
       
   586     if (qt_mac_create_fsref(filePath, &fsRef) == noErr) {
       
   587         AEDesc desc;
       
   588         if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr){
       
   589             if (AEPutDesc(&descList, 0, &desc) == noErr)
       
   590                 NavCustomControl(mDialog, kNavCtlSetSelection, (void*)&descList);
       
   591         }
       
   592     }
       
   593 
       
   594     // Type the file name into the save dialog's text field:
       
   595     UInt8 *strBuffer = (UInt8 *)malloc(1024);
       
   596     qt_mac_to_pascal_string(QFileInfo(filename).fileName(), strBuffer);
       
   597     NavCustomControl(mDialog, kNavCtlSetEditFileName, strBuffer);
       
   598     free(strBuffer);
       
   599 #else
       
   600     // There seems to no way to select a file once the dialog is running.
       
   601     // So do the next best thing, set the file's directory:
       
   602     setDirectory_sys(QFileInfo(filePath).absolutePath());
       
   603 #endif
       
   604 }
       
   605 
       
   606 QStringList QFileDialogPrivate::selectedFiles_sys() const
       
   607 {
       
   608 #ifndef QT_MAC_USE_COCOA
       
   609     if (q_func()->acceptMode() == QFileDialog::AcceptOpen){
       
   610         return mCurrentSelectionList;
       
   611     } else {
       
   612         return QStringList() << mCurrentLocation + QLatin1Char('/')
       
   613                                 + QCFString::toQString(NavDialogGetSaveFileName(mDialog));
       
   614     }
       
   615 #else
       
   616     QMacCocoaAutoReleasePool pool;
       
   617     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   618     return [delegate selectedFiles];
       
   619 #endif
       
   620 }
       
   621 
       
   622 void QFileDialogPrivate::setNameFilters_sys(const QStringList &filters)
       
   623 {
       
   624 #ifndef QT_MAC_USE_COCOA
       
   625     Q_UNUSED(filters);
       
   626 #else
       
   627     QMacCocoaAutoReleasePool pool;
       
   628     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   629     bool hideDetails = q_func()->testOption(QFileDialog::HideNameFilterDetails);
       
   630     [delegate setNameFilters:filters hideDetails:hideDetails];
       
   631 #endif
       
   632 }
       
   633 
       
   634 void QFileDialogPrivate::setFilter_sys()
       
   635 {
       
   636 #ifndef QT_MAC_USE_COCOA
       
   637 #else
       
   638     QMacCocoaAutoReleasePool pool;
       
   639     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   640     *(delegate->mQDirFilter) = model->filter();
       
   641     [delegate updateProperties];
       
   642 #endif
       
   643 }
       
   644 
       
   645 void QFileDialogPrivate::selectNameFilter_sys(const QString &filter)
       
   646 {
       
   647     int index = nameFilters.indexOf(filter);
       
   648     if (index != -1) {
       
   649 #ifndef QT_MAC_USE_COCOA
       
   650         NavMenuItemSpec navSpec;
       
   651         bzero(&navSpec, sizeof(NavMenuItemSpec));
       
   652         navSpec.menuType = index;
       
   653         NavCustomControl(mDialog, kNavCtlSelectCustomType, &navSpec);
       
   654 #else
       
   655         QMacCocoaAutoReleasePool pool;
       
   656         QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   657         [delegate->mPopUpButton selectItemAtIndex:index];
       
   658         [delegate filterChanged:nil];
       
   659 #endif
       
   660     }
       
   661 }
       
   662 
       
   663 QString QFileDialogPrivate::selectedNameFilter_sys() const
       
   664 {
       
   665 #ifndef QT_MAC_USE_COCOA
       
   666     int index = filterInfo.currentSelection;
       
   667 #else
       
   668     QMacCocoaAutoReleasePool pool;
       
   669     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
   670     int index = [delegate->mPopUpButton indexOfSelectedItem];
       
   671 #endif
       
   672     return index != -1 ? nameFilters.at(index) : QString();
       
   673 }
       
   674 
       
   675 void QFileDialogPrivate::deleteNativeDialog_sys()
       
   676 {
       
   677 #ifndef QT_MAC_USE_COCOA
       
   678     if (mDialog)
       
   679         NavDialogDispose(mDialog);
       
   680     mDialog = 0;
       
   681     mDialogStarted = false;
       
   682 #else
       
   683     QMacCocoaAutoReleasePool pool;
       
   684     [reinterpret_cast<QNSOpenSavePanelDelegate *>(mDelegate) release];
       
   685     mDelegate = 0;
       
   686 #endif
       
   687     nativeDialogInUse = false;
       
   688 }
       
   689 
       
   690 bool QFileDialogPrivate::setVisible_sys(bool visible)
       
   691 {
       
   692     Q_Q(QFileDialog);
       
   693     if (!visible == q->isHidden())
       
   694         return false;
       
   695 
       
   696 #ifndef QT_MAC_USE_COCOA
       
   697     return visible ? showCarbonNavServicesDialog() : hideCarbonNavServicesDialog();
       
   698 #else
       
   699     return visible ? showCocoaFilePanel() : hideCocoaFilePanel();
       
   700 #endif
       
   701 }
       
   702 
       
   703 #ifndef QT_MAC_USE_COCOA
       
   704 Boolean QFileDialogPrivate::qt_mac_filedialog_filter_proc(AEDesc *theItem, void *info,
       
   705                                                                  void *data, NavFilterModes)
       
   706 {
       
   707     QFileDialogPrivate *fileDialogPrivate = static_cast<QFileDialogPrivate *>(data);
       
   708 
       
   709     if (!fileDialogPrivate || fileDialogPrivate->filterInfo.filters.isEmpty()
       
   710         || (fileDialogPrivate->filterInfo.currentSelection < 0
       
   711                 && fileDialogPrivate->filterInfo.currentSelection
       
   712                         >= fileDialogPrivate->filterInfo.filters.size()))
       
   713         return true;
       
   714 
       
   715     NavFileOrFolderInfo *theInfo = static_cast<NavFileOrFolderInfo *>(info);
       
   716     QString file;
       
   717     const QtMacFilterName &fn
       
   718            = fileDialogPrivate->filterInfo.filters.at(fileDialogPrivate->filterInfo.currentSelection);
       
   719     if (theItem->descriptorType == typeFSRef) {
       
   720         FSRef ref;
       
   721         AEGetDescData(theItem, &ref, sizeof(ref));
       
   722         UInt8 str_buffer[1024];
       
   723         FSRefMakePath(&ref, str_buffer, 1024);
       
   724         file = QString::fromUtf8(reinterpret_cast<const char *>(str_buffer));
       
   725         int slsh = file.lastIndexOf(QLatin1Char('/'));
       
   726         if (slsh != -1)
       
   727             file = file.right(file.length() - slsh - 1);
       
   728     }
       
   729     QStringList reg = fn.regexp.split(QLatin1String(";"));
       
   730     for (QStringList::const_iterator it = reg.constBegin(); it != reg.constEnd(); ++it) {
       
   731         QRegExp rg(*it, Qt::CaseInsensitive, QRegExp::Wildcard);
       
   732 #ifdef DEBUG_FILEDIALOG_FILTERS
       
   733         qDebug("QFileDialogPrivate::qt_mac_filedialog_filter_proc:%d, asked to filter.. %s (%s)", __LINE__,
       
   734                 qPrintable(file), qPrintable(*it));
       
   735 #endif
       
   736         if (rg.exactMatch(file))
       
   737             return true;
       
   738     }
       
   739     return (theInfo->isFolder && !file.endsWith(QLatin1String(".app")));
       
   740 }
       
   741 
       
   742 void QFileDialogPrivate::qt_mac_filedialog_event_proc(const NavEventCallbackMessage msg,
       
   743         NavCBRecPtr p, NavCallBackUserData data)
       
   744 {
       
   745     QFileDialogPrivate *fileDialogPrivate = static_cast<QFileDialogPrivate *>(data);
       
   746 
       
   747     switch(msg) {
       
   748     case kNavCBPopupMenuSelect: {
       
   749         NavMenuItemSpec *s = static_cast<NavMenuItemSpec *>(p->eventData.eventDataParms.param);
       
   750         if (int(s->menuType) != fileDialogPrivate->filterInfo.currentSelection) {
       
   751             fileDialogPrivate->filterInfo.currentSelection = s->menuType;
       
   752             emit fileDialogPrivate->q_func()->filterSelected(fileDialogPrivate->nameFilters.at(s->menuType));
       
   753         }
       
   754         if (fileDialogPrivate->acceptMode == QFileDialog::AcceptSave) {
       
   755             QString base = QCFString::toQString(NavDialogGetSaveFileName(p->context));
       
   756             QFileInfo fi(base);
       
   757             base = fi.completeBaseName();
       
   758             const QtMacFilterName &fn = fileDialogPrivate->filterInfo.filters.at(
       
   759                                                        fileDialogPrivate->filterInfo.currentSelection);
       
   760             QStringList reg = fn.regexp.split(QLatin1String(";"), QString::SkipEmptyParts);
       
   761             QString r = reg.first();
       
   762             r  = r.right(r.length()-1);      // Strip the *
       
   763             base += r;                        //"." + QString::number(s->menuType);
       
   764             NavDialogSetSaveFileName(p->context, QCFString::toCFStringRef(base));
       
   765         }
       
   766 #ifdef DEBUG_FILEDIALOG_FILTERS
       
   767         qDebug("QFileDialogPrivate::qt_mac_filedialog_event_proc:%d - Selected a filter: %ld", __LINE__, s->menuType);
       
   768 #endif
       
   769         break; }
       
   770     case kNavCBStart:{
       
   771         fileDialogPrivate->mDialogStarted = true;
       
   772         // Set selected file:
       
   773         QModelIndexList indexes = fileDialogPrivate->qFileDialogUi->listView->selectionModel()->selectedRows();
       
   774         QString selected;
       
   775         if (!indexes.isEmpty())
       
   776             selected = indexes.at(0).data(QFileSystemModel::FilePathRole).toString();
       
   777         else
       
   778             selected = fileDialogPrivate->typedFiles().value(0);
       
   779         fileDialogPrivate->selectFile_sys(selected);
       
   780         fileDialogPrivate->selectNameFilter_sys(fileDialogPrivate->qFileDialogUi->fileTypeCombo->currentText());
       
   781         break; }
       
   782     case kNavCBSelectEntry:{
       
   783         // Event: Current selection has changed.
       
   784         QStringList prevSelectionList = fileDialogPrivate->mCurrentSelectionList;
       
   785         fileDialogPrivate->mCurrentSelectionList.clear();
       
   786         QString fileNameToEmit;
       
   787 
       
   788         AEDescList *descList = (AEDescList *)p->eventData.eventDataParms.param;
       
   789         // Get the number of files selected:
       
   790         UInt8 strBuffer[1024];
       
   791         long count;
       
   792         OSErr err = AECountItems(descList, &count);
       
   793         if (err != noErr || !count)
       
   794             break;
       
   795 
       
   796         for (long index=1; index<=count; ++index) {
       
   797             FSRef ref;
       
   798             err = AEGetNthPtr(descList, index, typeFSRef, 0, 0, &ref, sizeof(ref), 0);
       
   799             if (err != noErr)
       
   800                 break;
       
   801             FSRefMakePath(&ref, strBuffer, 1024);
       
   802             QString selected = QString::fromUtf8((const char *)strBuffer);
       
   803             fileDialogPrivate->mCurrentSelectionList << selected;
       
   804             if (!prevSelectionList.contains(selected))
       
   805                 fileNameToEmit = selected;
       
   806         }
       
   807 
       
   808         if (!fileNameToEmit.isEmpty() && fileNameToEmit != fileDialogPrivate->mCurrentSelection)
       
   809             emit fileDialogPrivate->q_func()->currentChanged(fileNameToEmit);
       
   810         fileDialogPrivate->mCurrentSelection = fileNameToEmit;
       
   811         break; }
       
   812     case kNavCBShowDesktop:
       
   813     case kNavCBNewLocation:{
       
   814         // Event: Current directory has changed.
       
   815         AEDesc *desc = (AEDesc *)p->eventData.eventDataParms.param;
       
   816         FSRef ref;
       
   817         AEGetDescData(desc, &ref, sizeof(ref));
       
   818         UInt8 *strBuffer = (UInt8 *)malloc(1024);
       
   819         FSRefMakePath(&ref, strBuffer, 1024);
       
   820         QString newLocation = QString::fromUtf8((const char *)strBuffer);
       
   821         free(strBuffer);
       
   822         if (fileDialogPrivate->mCurrentLocation != newLocation){
       
   823             fileDialogPrivate->mCurrentLocation = newLocation;
       
   824             QFileDialog::FileMode mode = fileDialogPrivate->fileMode;
       
   825             if (mode == QFileDialog::AnyFile || mode == QFileDialog::ExistingFile
       
   826                     || mode == QFileDialog::ExistingFiles){
       
   827                 // When changing directory, the current selection is cleared if
       
   828                 // we are supposed to be selecting files only:
       
   829                 fileDialogPrivate->mCurrentSelectionList.clear();
       
   830                 if (!fileDialogPrivate->mCurrentSelection.isEmpty()){
       
   831                     fileDialogPrivate->mCurrentSelection.clear();
       
   832                     emit fileDialogPrivate->q_func()->currentChanged(fileDialogPrivate->mCurrentSelection);
       
   833                 }
       
   834             }
       
   835             fileDialogPrivate->setLastVisitedDirectory(newLocation);
       
   836             emit fileDialogPrivate->q_func()->directoryEntered(newLocation);
       
   837         }
       
   838         break; }
       
   839     case kNavCBAccept:
       
   840         fileDialogPrivate->mDialogClosed = true;
       
   841         fileDialogPrivate->q_func()->accept();
       
   842         break;
       
   843     case kNavCBCancel:
       
   844         fileDialogPrivate->mDialogClosed = true;
       
   845         fileDialogPrivate->q_func()->reject();
       
   846         break;
       
   847     }
       
   848 }
       
   849 
       
   850 static QFileDialogPrivate::QtMacFilterName qt_mac_extract_filter(const QString &rawFilter, bool showDetails)
       
   851 {
       
   852     QFileDialogPrivate::QtMacFilterName ret;
       
   853     ret.filter = rawFilter;
       
   854     QString result = rawFilter;
       
   855     QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
       
   856     int index = r.indexIn(result);
       
   857     if (index >= 0)
       
   858         result = r.cap(2);
       
   859 
       
   860     if (showDetails) {
       
   861         ret.description = rawFilter;
       
   862     } else {
       
   863         if (index >= 0)
       
   864             ret.description = r.cap(1).trimmed();
       
   865         if (ret.description.isEmpty())
       
   866             ret.description = result;
       
   867     }
       
   868     ret.regexp = result.replace(QLatin1Char(' '), QLatin1Char(';'));
       
   869     return ret;
       
   870 }
       
   871 
       
   872 static QList<QFileDialogPrivate::QtMacFilterName> qt_mac_make_filters_list(const QString &filter, bool showDetails)
       
   873 {
       
   874 #ifdef DEBUG_FILEDIALOG_FILTERS
       
   875     qDebug("QFileDialog:%d - Got filter (%s)", __LINE__, filter.latin1());
       
   876 #endif
       
   877 
       
   878     QList<QFileDialogPrivate::QtMacFilterName> ret;
       
   879     QString f(filter);
       
   880     if (f.isEmpty())
       
   881         f = QFileDialog::tr("All Files (*)");
       
   882     if (f.isEmpty())
       
   883         return ret;
       
   884     QStringList filts = qt_make_filter_list(f);
       
   885     for (QStringList::const_iterator it = filts.constBegin(); it != filts.constEnd(); ++it) {
       
   886         QFileDialogPrivate::QtMacFilterName filter = qt_mac_extract_filter(*it, showDetails);
       
   887 #ifdef DEBUG_FILEDIALOG_FILTERS
       
   888         qDebug("QFileDialog:%d Split out filter (%d) '%s' '%s' [%s]", __LINE__, ret.count(),
       
   889                 filter->regxp.latin1(), filter->description.latin1(), (*it).latin1());
       
   890 #endif
       
   891         ret.append(filter);
       
   892     }
       
   893     return ret;
       
   894 }
       
   895 
       
   896 void QFileDialogPrivate::createNavServicesDialog()
       
   897 {
       
   898     Q_Q(QFileDialog);
       
   899     if (mDialog)
       
   900         deleteNativeDialog_sys();
       
   901 
       
   902     NavDialogCreationOptions navOptions;
       
   903     NavGetDefaultDialogCreationOptions(&navOptions);
       
   904 
       
   905     // Translate QFileDialog settings into NavDialog options:
       
   906     if (qt_mac_is_macsheet(q)) {
       
   907         navOptions.modality = kWindowModalityWindowModal;
       
   908         navOptions.parentWindow = qt_mac_window_for(q->parentWidget());
       
   909     } else if (q->windowModality() ==  Qt::ApplicationModal)
       
   910         navOptions.modality = kWindowModalityAppModal;
       
   911     else
       
   912         navOptions.modality = kWindowModalityNone;
       
   913     navOptions.optionFlags |= kNavSupportPackages;
       
   914     if (q->testOption(QFileDialog::DontConfirmOverwrite))
       
   915         navOptions.optionFlags |= kNavDontConfirmReplacement;
       
   916     if (fileMode != QFileDialog::ExistingFiles)
       
   917         navOptions.optionFlags &= ~kNavAllowMultipleFiles;
       
   918 
       
   919     navOptions.windowTitle = QCFString::toCFStringRef(q->windowTitle());
       
   920 
       
   921     navOptions.location.h = -1;
       
   922     navOptions.location.v = -1;
       
   923 
       
   924     QWidget *parent = q->parentWidget();
       
   925     if (parent && parent->isVisible()) {
       
   926         WindowClass wclass;
       
   927         GetWindowClass(qt_mac_window_for(parent), &wclass);
       
   928         parent = parent->window();
       
   929         QString s = parent->windowTitle();
       
   930         navOptions.clientName = QCFString::toCFStringRef(s);
       
   931     }
       
   932 
       
   933     filterInfo.currentSelection = 0;
       
   934     filterInfo.filters = qt_mac_make_filters_list(nameFilters.join(QLatin1String(";;")), q->isNameFilterDetailsVisible());
       
   935     QCFType<CFArrayRef> filterArray;
       
   936     if (filterInfo.filters.size() > 1) {
       
   937         int i = 0;
       
   938         CFStringRef *cfstringArray = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)
       
   939                                                                    * filterInfo.filters.size()));
       
   940         for (i = 0; i < filterInfo.filters.size(); ++i) {
       
   941             cfstringArray[i] = QCFString::toCFStringRef(filterInfo.filters.at(i).description);
       
   942         }
       
   943         filterArray = CFArrayCreate(kCFAllocatorDefault,
       
   944                         reinterpret_cast<const void **>(cfstringArray), filterInfo.filters.size(),
       
   945                         &kCFTypeArrayCallBacks);
       
   946         navOptions.popupExtension = filterArray;
       
   947         free(cfstringArray);
       
   948     }
       
   949 
       
   950     if (q->acceptMode() == QFileDialog::AcceptSave) {
       
   951         if (NavCreatePutFileDialog(&navOptions, 'cute', kNavGenericSignature,
       
   952                     QFileDialogPrivate::qt_mac_filedialog_event_proc, this, &mDialog)) {
       
   953             qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
       
   954             return;
       
   955         }
       
   956     } else if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) {
       
   957         if (NavCreateChooseFolderDialog(&navOptions,
       
   958                     QFileDialogPrivate::qt_mac_filedialog_event_proc, 0, this, &mDialog)) {
       
   959             qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
       
   960             return;
       
   961         }
       
   962     } else {
       
   963         if (NavCreateGetFileDialog(&navOptions, 0,
       
   964                     QFileDialogPrivate::qt_mac_filedialog_event_proc, 0,
       
   965                     QFileDialogPrivate::qt_mac_filedialog_filter_proc, this, &mDialog)) {
       
   966             qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
       
   967             return;
       
   968         }
       
   969     }
       
   970 
       
   971     // Set start-up directory:
       
   972     if (mCurrentLocation.isEmpty())
       
   973         mCurrentLocation = rootPath();
       
   974     FSRef fsRef;
       
   975     if (qt_mac_create_fsref(mCurrentLocation, &fsRef) == noErr) {
       
   976         AEDesc desc;
       
   977         if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr)
       
   978             NavCustomControl(mDialog, kNavCtlSetLocation, (void*)&desc);
       
   979     }
       
   980 }
       
   981 
       
   982 bool QFileDialogPrivate::showCarbonNavServicesDialog()
       
   983 {
       
   984     Q_Q(QFileDialog);
       
   985     if (q->acceptMode() == QFileDialog::AcceptSave && q->windowModality() == Qt::NonModal)
       
   986         return false; // cannot do native no-modal save dialogs.
       
   987     createNavServicesDialog();
       
   988     mDialogClosed = false;
       
   989     if (q->windowModality() != Qt::ApplicationModal)
       
   990         NavDialogRun(mDialog);
       
   991     return true;
       
   992 }
       
   993 
       
   994 bool QFileDialogPrivate::hideCarbonNavServicesDialog()
       
   995 {
       
   996     if (!mDialogClosed){
       
   997         mDialogClosed = true;
       
   998         NavCustomControl(mDialog, kNavCtlCancel, 0);
       
   999     }
       
  1000     return true;
       
  1001 }
       
  1002 
       
  1003 #else // Cocoa
       
  1004 
       
  1005 void QFileDialogPrivate::createNSOpenSavePanelDelegate()
       
  1006 {
       
  1007     Q_Q(QFileDialog);
       
  1008     if (mDelegate)
       
  1009         return;
       
  1010 
       
  1011     bool selectDir = q->selectedFiles().isEmpty();
       
  1012     QString selection(selectDir ? q->directory().absolutePath() : q->selectedFiles().value(0));
       
  1013     QNSOpenSavePanelDelegate *delegate = [[QNSOpenSavePanelDelegate alloc]
       
  1014         initWithAcceptMode:acceptMode
       
  1015         title:q->windowTitle()
       
  1016         nameFilters:q->nameFilters()
       
  1017         selectedNameFilter:q->selectedNameFilter()
       
  1018         hideNameFilterDetails:q->testOption(QFileDialog::HideNameFilterDetails)
       
  1019         qDirFilter:model->filter()
       
  1020         fileOptions:opts
       
  1021         fileMode:fileMode
       
  1022         selectFile:selection
       
  1023         confirmOverwrite:!q->testOption(QFileDialog::DontConfirmOverwrite)
       
  1024         priv:this];
       
  1025 
       
  1026     mDelegate = delegate;
       
  1027 }
       
  1028 
       
  1029 bool QFileDialogPrivate::showCocoaFilePanel()
       
  1030 {
       
  1031     Q_Q(QFileDialog);
       
  1032     QMacCocoaAutoReleasePool pool;
       
  1033     createNSOpenSavePanelDelegate();
       
  1034     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
  1035     if (qt_mac_is_macsheet(q))
       
  1036         [delegate showWindowModalSheet:q->parentWidget()];
       
  1037     else
       
  1038         [delegate showModelessPanel];
       
  1039     return true;
       
  1040 }
       
  1041 
       
  1042 bool QFileDialogPrivate::hideCocoaFilePanel()
       
  1043 {
       
  1044     if (!mDelegate){
       
  1045         // Nothing to do. We return false to leave the question
       
  1046         // open regarding whether or not to go native:
       
  1047         return false;
       
  1048     } else {
       
  1049         QMacCocoaAutoReleasePool pool;
       
  1050         QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
  1051         [delegate closePanel];
       
  1052         // Even when we hide it, we are still using a
       
  1053         // native dialog, so return true:
       
  1054         return true;
       
  1055     }
       
  1056 }
       
  1057 
       
  1058 #endif
       
  1059 
       
  1060 void QFileDialogPrivate::mac_nativeDialogModalHelp()
       
  1061 {
       
  1062     // Do a queued meta-call to open the native modal dialog so it opens after the new
       
  1063     // event loop has started to execute (in QDialog::exec). Using a timer rather than
       
  1064     // a queued meta call is intentional to ensure that the call is only delivered when
       
  1065     // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
       
  1066     // running (which is the case if e.g a top-most QEventLoop has been
       
  1067     // interrupted, and the second-most event loop has not yet been reactivated (regardless
       
  1068     // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
       
  1069     if (nativeDialogInUse){
       
  1070         Q_Q(QFileDialog);
       
  1071         QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel()));
       
  1072     }
       
  1073 }
       
  1074 
       
  1075 void QFileDialogPrivate::_q_macRunNativeAppModalPanel()
       
  1076 {
       
  1077     QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
       
  1078 #ifndef QT_MAC_USE_COCOA
       
  1079     NavDialogRun(mDialog);
       
  1080 #else
       
  1081     Q_Q(QFileDialog);
       
  1082     QMacCocoaAutoReleasePool pool;
       
  1083     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
  1084     [delegate runApplicationModalPanel];
       
  1085     dialogResultCode_sys() == QDialog::Accepted ? q->accept() : q->reject();
       
  1086 #endif
       
  1087 }
       
  1088 
       
  1089 QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys()
       
  1090 {
       
  1091 #ifndef QT_MAC_USE_COCOA
       
  1092     NavUserAction result = NavDialogGetUserAction(mDialog);
       
  1093     if (result == kNavUserActionCancel || result == kNavUserActionNone)
       
  1094         return QDialog::Rejected;
       
  1095     else
       
  1096         return QDialog::Accepted;
       
  1097 #else
       
  1098     QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate);
       
  1099     return [delegate dialogResultCode];
       
  1100 #endif
       
  1101 }
       
  1102 
       
  1103 
       
  1104 QT_END_NAMESPACE
       
  1105 
       
  1106 #endif // QT_NO_FILEDIALOG
       
  1107