X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1b447793ea73455bcec70ee39db841b28e6fc7cf..7c60222510bc5e197b12f153c4bf05db66cb0f4a:/src/osx/cocoa/filedlg.mm diff --git a/src/osx/cocoa/filedlg.mm b/src/osx/cocoa/filedlg.mm index c212ecea36..40d4f4645f 100644 --- a/src/osx/cocoa/filedlg.mm +++ b/src/osx/cocoa/filedlg.mm @@ -4,7 +4,7 @@ // Author: Ryan Norton // Modified by: // Created: 2004-10-02 -// RCS-ID: $Id: filedlg.mm 40007 2006-07-05 13:10:46Z SC $ +// RCS-ID: $Id$ // Copyright: (c) Ryan Norton // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -27,360 +27,681 @@ #ifndef WX_PRECOMP #include "wx/msgdlg.h" #include "wx/app.h" + #include "wx/sizer.h" + #include "wx/stattext.h" + #include "wx/choice.h" #endif #include "wx/filename.h" +#include "wx/tokenzr.h" +#include "wx/evtloop.h" #include "wx/osx/private.h" +#include "wx/sysopt.h" +#include "wx/modalhook.h" + +#include // ============================================================================ // implementation // ============================================================================ -IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) +// Open Items: +// - parameter support for descending into packages as directories (setTreatsFilePackagesAsDirectories) +// - as setAllowedFileTypes is only functional for NSOpenPanel on 10.6+, on earlier systems, the file +// type choice will not be shown, but all possible file items will be shown, if a popup must be working +// then the delegate method - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename will have to +// be implemented -wxFileDialog::wxFileDialog( - wxWindow *parent, const wxString& message, - const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard, - long style, const wxPoint& pos, const wxSize& sz, const wxString& name) - : wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name) +namespace +{ + +bool HasAppKit_10_6() { + // Even if we require 10.6, we might be loaded by an application that + // was linked against 10.5. setAllowedFileTypes will still be ignored + // in this case. From NSSavePanel.h: + // NSOpenPanel: On versions less than 10.6, this property is ignored. + // For applications that link against 10.6 and higher, this property will + // determine which files should be enabled in the open panel. + int32_t version = NSVersionOfLinkTimeLibrary("AppKit"); + if (version == -1) + { + // If we're loaded by an application that doesn't link against AppKit, + // use the runtime version instead. This check will not work for the + // case above. + version = NSVersionOfRunTimeLibrary("AppKit"); + } + + // Notice that this still works correctly even if version is -1. + return version >= 0x40e2400 /* version of 10.6 AppKit */; } +} // anonymous namespace -NSArray* GetTypesFromFilter( const wxString filter ) +@interface wxOpenPanelDelegate : NSObject wxOSX_10_6_AND_LATER() { - NSMutableArray* types = nil; - if ( !filter.empty() ) - { - wxArrayString names ; - wxArrayString extensions; + wxFileDialog* _dialog; +} + +- (wxFileDialog*) fileDialog; +- (void) setFileDialog:(wxFileDialog*) dialog; - wxString filter2(filter) ; - int filterIndex = 0; - bool isName = true ; - wxString current ; +- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename; - for ( unsigned int i = 0; i < filter2.length() ; i++ ) +@end + +@implementation wxOpenPanelDelegate + +- (id) init +{ + self = [super init]; + _dialog = NULL; + return self; +} + +- (wxFileDialog*) fileDialog +{ + return _dialog; +} + +- (void) setFileDialog:(wxFileDialog*) dialog +{ + _dialog = dialog; +} + +- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename +{ + BOOL showObject = YES; + + NSString* resolvedLink = [[NSFileManager defaultManager] pathContentOfSymbolicLinkAtPath:filename]; + if ( resolvedLink != nil ) + filename = resolvedLink; + + NSDictionary* fileAttribs = [[NSFileManager defaultManager] + fileAttributesAtPath:filename traverseLink:YES]; + if (fileAttribs) + { + // check for packages + if ([NSFileTypeDirectory isEqualTo:[fileAttribs objectForKey:NSFileType]]) { - if ( filter2.GetChar(i) == wxT('|') ) + if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO) + showObject = YES; // it's a folder, OK to show + else { - if ( isName ) - { - names.Add( current ) ; - } - else + // it's a packaged directory, apply check + wxCFStringRef filecf([filename retain]); + showObject = _dialog->CheckFile(filecf.AsString()); + } + } + else + { + // the code above only solves links, not aliases, do this here: + + NSString* resolvedAlias = nil; + + CFURLRef url = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, + (CFStringRef)filename, + kCFURLPOSIXPathStyle, + NO); + if (url != NULL) + { + FSRef fsRef; + if (CFURLGetFSRef(url, &fsRef)) { - extensions.Add( current ) ; - ++filterIndex ; + Boolean targetIsFolder, wasAliased; + OSErr err = FSResolveAliasFile (&fsRef, true, &targetIsFolder, &wasAliased); + + if ((err == noErr) && wasAliased) + { + CFURLRef resolvedUrl = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsRef); + if (resolvedUrl != NULL) + { + resolvedAlias = (NSString*) CFURLCopyFileSystemPath(resolvedUrl, + kCFURLPOSIXPathStyle); + CFRelease(resolvedUrl); + } + } } + CFRelease(url); + } - isName = !isName ; - current = wxEmptyString ; + if (resolvedAlias != nil) + { + // recursive call + [resolvedAlias autorelease]; + showObject = [self panel:sender shouldShowFilename:resolvedAlias]; } else { - current += filter2.GetChar(i) ; + wxCFStringRef filecf([filename retain]); + showObject = _dialog->CheckFile(filecf.AsString()); } } - // we allow for compatibility reason to have a single filter expression (like *.*) without - // an explanatory text, in that case the first part is name and extension at the same time + } - wxASSERT_MSG( filterIndex == 0 || !isName , wxT("incorrect format of format string") ) ; - if ( current.empty() ) - extensions.Add( names[filterIndex] ) ; - else - extensions.Add( current ) ; - if ( filterIndex == 0 || isName ) - names.Add( current ) ; + return showObject; +} - ++filterIndex ; +@end - const size_t extCount = extensions.GetCount(); - for ( size_t i = 0 ; i < extCount; i++ ) - { - wxString extension = extensions[i]; +IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) + +wxFileDialog::wxFileDialog( + wxWindow *parent, const wxString& message, + const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard, + long style, const wxPoint& pos, const wxSize& sz, const wxString& name) + : wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name) +{ + m_filterIndex = -1; + m_sheetDelegate = [[ModalDialogDelegate alloc] init]; + [(ModalDialogDelegate*)m_sheetDelegate setImplementation: this]; + m_delegate = nil; +} - // Remove leading '*' - if (extension.length() && (extension.GetChar(0) == '*')) - extension = extension.Mid( 1 ); +wxFileDialog::~wxFileDialog() +{ + [m_sheetDelegate release]; +} - // Remove leading '.' - if (extension.length() && (extension.GetChar(0) == '.')) - extension = extension.Mid( 1 ); +bool wxFileDialog::SupportsExtraControl() const +{ + return true; +} - if ( extension.IsEmpty() ) - { - if ( types != nil ) - [types release]; - return nil; - } +NSArray* GetTypesFromExtension( const wxString extensiongroup, wxArrayString& extensions ) +{ + NSMutableArray* types = nil; + extensions.Clear(); + wxStringTokenizer tokenizer( extensiongroup, wxT(";") ) ; + while ( tokenizer.HasMoreTokens() ) + { + wxString extension = tokenizer.GetNextToken() ; + // Remove leading '*' + if ( extension.length() && (extension.GetChar(0) == '*') ) + extension = extension.Mid( 1 ); - if ( types == nil ) - types = [[NSMutableArray alloc] init]; + // Remove leading '.' + if ( extension.length() && (extension.GetChar(0) == '.') ) + extension = extension.Mid( 1 ); - wxCFStringRef cfext(extension); - [types addObject: (NSString*)cfext.AsNSString() ]; -#if 0 - wxUint32 fileType, creator; + // Remove leading '*', this is for handling *.* + if ( extension.length() && (extension.GetChar(0) == '*') ) + extension = extension.Mid( 1 ); - // extension -> mactypes -#endif + if ( extension.IsEmpty() ) + { + extensions.Clear(); + [types release]; + types = nil; + return nil; } + + if ( types == nil ) + types = [[NSMutableArray alloc] init]; + + extensions.Add(extension.Lower()); + wxCFStringRef cfext(extension); + [types addObject: (NSString*)cfext.AsNSString() ]; +#if 0 + // add support for classic fileType / creator here + wxUint32 fileType, creator; + // extension -> mactypes +#endif } + [types autorelease]; return types; } -int wxFileDialog::ShowModal() +NSArray* GetTypesFromFilter( const wxString& filter, wxArrayString& names, wxArrayString& extensiongroups ) { - int result = wxID_CANCEL; + NSMutableArray* types = nil; + bool allowAll = false; - NSSavePanel *panel = nil; + names.Clear(); + extensiongroups.Clear(); - wxCFStringRef cf( m_message ); + if ( !filter.empty() ) + { + wxStringTokenizer tokenizer( filter, wxT("|") ); + int numtokens = (int)tokenizer.CountTokens(); + if(numtokens == 1) + { + // we allow for compatibility reason to have a single filter expression (like *.*) without + // an explanatory text, in that case the first part is name and extension at the same time + wxString extension = tokenizer.GetNextToken(); + names.Add( extension ); + extensiongroups.Add( extension ); + } + else + { + int numextensions = numtokens / 2; + for(int i = 0; i < numextensions; i++) + { + wxString name = tokenizer.GetNextToken(); + wxString extension = tokenizer.GetNextToken(); + names.Add( name ); + extensiongroups.Add( extension ); + } + } + const size_t extCount = extensiongroups.GetCount(); + wxArrayString extensions; + for ( size_t i = 0 ; i < extCount; i++ ) + { + NSArray* exttypes = GetTypesFromExtension(extensiongroups[i], extensions); + if ( exttypes != nil ) + { + if ( allowAll == false ) + { + if ( types == nil ) + types = [[NSMutableArray alloc] init]; + + [types addObjectsFromArray:exttypes]; + } + } + else + { + allowAll = true; + [types release]; + types = nil; + } + } + } + [types autorelease]; + return types; +} + +void wxFileDialog::ShowWindowModal() +{ + wxCFStringRef cf( m_message ); wxCFStringRef dir( m_dir ); wxCFStringRef file( m_fileName ); - m_path = wxEmptyString; - m_fileNames.Clear(); + wxNonOwnedWindow* parentWindow = NULL; + + m_modality = wxDIALOG_MODALITY_WINDOW_MODAL; - if (HasFlag(wxFD_SAVE)) + if (GetParent()) + parentWindow = dynamic_cast(wxGetTopLevelParent(GetParent())); + + wxASSERT_MSG(parentWindow, "Window modal display requires parent."); + + NSArray* types = GetTypesFromFilter( m_wildCard, m_filterNames, m_filterExtensions ) ; + if ( HasFlag(wxFD_SAVE) ) { NSSavePanel* sPanel = [NSSavePanel savePanel]; + + SetupExtraControls(sPanel); + // makes things more convenient: [sPanel setCanCreateDirectories:YES]; [sPanel setMessage:cf.AsNSString()]; + // if we should be able to descend into pacakges we must somehow + // be able to pass this in [sPanel setTreatsFilePackagesAsDirectories:NO]; - - if ( HasFlag(wxFD_OVERWRITE_PROMPT) ) - { - } - - if ( [sPanel runModalForDirectory:dir.AsNSString() file:file.AsNSString() ] == NSOKButton ) - { - panel = sPanel; - result = wxID_OK; - - wxCFStringRef filename( [[sPanel filename] retain] ); - - m_path = filename.AsString(); - m_fileName = wxFileNameFromPath(m_path); - m_dir = wxPathOnly( m_path ); - } + [sPanel setCanSelectHiddenExtension:YES]; + [sPanel setAllowedFileTypes:types]; + [sPanel setAllowsOtherFileTypes:NO]; + + NSWindow* nativeParent = parentWindow->GetWXWindow(); + [sPanel beginSheetForDirectory:dir.AsNSString() file:file.AsNSString() + modalForWindow: nativeParent modalDelegate: m_sheetDelegate + didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo: nil]; } - else + else { - NSArray* types = GetTypesFromFilter( m_wildCard ) ; NSOpenPanel* oPanel = [NSOpenPanel openPanel]; + + SetupExtraControls(oPanel); + [oPanel setTreatsFilePackagesAsDirectories:NO]; [oPanel setCanChooseDirectories:NO]; [oPanel setResolvesAliases:YES]; [oPanel setCanChooseFiles:YES]; [oPanel setMessage:cf.AsNSString()]; + [oPanel setAllowsMultipleSelection: (HasFlag(wxFD_MULTIPLE) ? YES : NO )]; + + NSWindow* nativeParent = parentWindow->GetWXWindow(); + [oPanel beginSheetForDirectory:dir.AsNSString() file:file.AsNSString() + types: types modalForWindow: nativeParent + modalDelegate: m_sheetDelegate + didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo: nil]; + } +} + +// Create a panel with the file type drop down list +// If extra controls need to be added (see wxFileDialog::SetExtraControlCreator), add +// them to the panel as well +// Returns the newly created wxPanel - if ( [oPanel runModalForDirectory:dir.AsNSString() file:file.AsNSString() types:types] == NSOKButton ) +wxWindow* wxFileDialog::CreateFilterPanel(wxWindow *extracontrol) +{ + wxPanel *extrapanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); + wxBoxSizer *verticalSizer = new wxBoxSizer(wxVERTICAL); + extrapanel->SetSizer(verticalSizer); + + // the file type control + { + wxBoxSizer *horizontalSizer = new wxBoxSizer(wxHORIZONTAL); + verticalSizer->Add(horizontalSizer, 0, wxEXPAND, 0); + wxStaticText *stattext = new wxStaticText( extrapanel, wxID_ANY, _("File type:") ); + horizontalSizer->Add(stattext, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + m_filterChoice = new wxChoice(extrapanel, wxID_ANY); + horizontalSizer->Add(m_filterChoice, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5); + m_filterChoice->Append(m_filterNames); + if( m_filterNames.GetCount() > 0) { - panel = oPanel; - result = wxID_OK; - NSArray* filenames = [oPanel filenames]; - for ( size_t i = 0 ; i < [filenames count] ; ++ i ) + if ( m_firstFileTypeFilter >= 0 ) + m_filterChoice->SetSelection(m_firstFileTypeFilter); + } + m_filterChoice->Connect(wxEVT_CHOICE, wxCommandEventHandler(wxFileDialog::OnFilterSelected), NULL, this); + } + + if(extracontrol) + { + wxBoxSizer *horizontalSizer = new wxBoxSizer(wxHORIZONTAL); + verticalSizer->Add(horizontalSizer, 0, wxEXPAND, 0); + + extracontrol->Reparent(extrapanel); + horizontalSizer->Add(extracontrol); + } + + verticalSizer->Layout(); + verticalSizer->SetSizeHints(extrapanel); + return extrapanel; +} + +void wxFileDialog::DoOnFilterSelected(int index) +{ + NSArray* types = GetTypesFromExtension(m_filterExtensions[index],m_currentExtensions); + NSSavePanel* panel = (NSSavePanel*) GetWXWindow(); + if ( m_delegate ) + [panel validateVisibleColumns]; + else + [panel setAllowedFileTypes:types]; +} + +// An item has been selected in the file filter wxChoice: +void wxFileDialog::OnFilterSelected( wxCommandEvent &WXUNUSED(event) ) +{ + DoOnFilterSelected( m_filterChoice->GetSelection() ); +} + +bool wxFileDialog::CheckFile( const wxString& filename ) +{ + if ( m_currentExtensions.GetCount() == 0 ) + return true; + + wxString ext = filename.AfterLast('.').Lower(); + + for ( size_t i = 0; i < m_currentExtensions.GetCount(); ++i ) + { + if ( ext == m_currentExtensions[i] ) + return true; + } + return false; +} + +void wxFileDialog::SetupExtraControls(WXWindow nativeWindow) +{ + NSSavePanel* panel = (NSSavePanel*) nativeWindow; + // for sandboxed app we cannot access the outer structures + // this leads to problems with extra controls, so as a temporary + // workaround for crashes we don't support those yet + if ( [panel contentView] == nil ) + return; + + wxNonOwnedWindow::Create( GetParent(), nativeWindow ); + wxWindow* extracontrol = NULL; + if ( HasExtraControlCreator() ) + { + CreateExtraControl(); + extracontrol = GetExtraControl(); + } + + NSView* accView = nil; + + if ( m_useFileTypeFilter ) + { + m_filterPanel = CreateFilterPanel(extracontrol); + accView = m_filterPanel->GetHandle(); + if( HasFlag(wxFD_OPEN) ) + { + if ( UMAGetSystemVersion() < 0x1060 || !HasAppKit_10_6() ) { - wxCFStringRef filename( [(NSString*) [filenames objectAtIndex:i] retain] ); - wxString fnstr = filename.AsString(); - m_paths.Add( fnstr ); - m_fileNames.Add( wxFileNameFromPath(fnstr) ); - if ( i == 0 ) - { - m_path = fnstr; - m_fileName = wxFileNameFromPath(fnstr); - m_dir = wxPathOnly( fnstr ); - } + wxOpenPanelDelegate* del = [[wxOpenPanelDelegate alloc]init]; + [del setFileDialog:this]; + [panel setDelegate:del]; + m_delegate = del; } } - if ( types != nil ) - [types release]; + } + else + { + m_filterPanel = NULL; + m_filterChoice = NULL; + if ( extracontrol != nil ) + accView = extracontrol->GetHandle(); } - return result; + if ( accView != nil ) + { + [accView removeFromSuperview]; + [panel setAccessoryView:accView]; + } + else + { + [panel setAccessoryView:nil]; + } } -#if 0 +int wxFileDialog::ShowModal() +{ + WX_HOOK_MODAL_DIALOG(); - wxASSERT(CreateBase(parent,wxID_ANY,pos,wxDefaultSize,style,wxDefaultValidator,wxDialogNameStr)); + wxCFEventLoopPauseIdleEvents pause; - if ( parent ) - parent->AddChild(this); + wxMacAutoreleasePool autoreleasepool; + + wxCFStringRef cf( m_message ); - m_cocoaNSWindow = nil; - m_cocoaNSView = nil; + wxCFStringRef dir( m_dir ); + wxCFStringRef file( m_fileName ); + + m_path = wxEmptyString; + m_fileNames.Clear(); + m_paths.Clear(); - //Init the wildcard array - m_wildcards = [[NSMutableArray alloc] initWithCapacity:0]; + wxNonOwnedWindow* parentWindow = NULL; + int returnCode = -1; - //If the user requests to save - use a NSSavePanel - //else use a NSOpenPanel - if (HasFlag(wxFD_SAVE)) + if (GetParent()) { - SetNSPanel([NSSavePanel savePanel]); + parentWindow = dynamic_cast(wxGetTopLevelParent(GetParent())); + } + - [GetNSSavePanel() setTitle:wxNSStringWithWxString(message)]; + NSArray* types = GetTypesFromFilter( m_wildCard, m_filterNames, m_filterExtensions ) ; - [GetNSSavePanel() setPrompt:@"Save"]; - [GetNSSavePanel() setTreatsFilePackagesAsDirectories:YES]; - [GetNSSavePanel() setCanSelectHiddenExtension:YES]; + m_useFileTypeFilter = m_filterExtensions.GetCount() > 1; -// Cached as per-app in obj-c -// [GetNSSavePanel() setExtensionHidden:YES]; + if( HasFlag(wxFD_OPEN) ) + { + if ( !(wxSystemOptions::HasOption( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES ) && (wxSystemOptions::GetOptionInt( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES ) == 1)) ) + m_useFileTypeFilter = false; + } + + m_firstFileTypeFilter = -1; - // - // NB: Note that only Panther supports wildcards - // with save dialogs - not that wildcards in save - // dialogs are all that useful, anyway :) - // + if ( m_useFileTypeFilter + && m_filterIndex >= 0 && m_filterIndex < m_filterExtensions.GetCount() ) + { + m_firstFileTypeFilter = m_filterIndex; } - else //m_dialogStyle & wxFD_OPEN + else if ( m_useFileTypeFilter ) { - SetNSPanel([NSOpenPanel openPanel]); - [m_cocoaNSWindow setTitle:wxNSStringWithWxString(message)]; - - [(NSOpenPanel*)m_cocoaNSWindow setAllowsMultipleSelection:(HasFlag(wxFD_MULTIPLE))]; - [(NSOpenPanel*)m_cocoaNSWindow setResolvesAliases:YES]; - [(NSOpenPanel*)m_cocoaNSWindow setCanChooseFiles:YES]; - [(NSOpenPanel*)m_cocoaNSWindow setCanChooseDirectories:NO]; - [GetNSSavePanel() setPrompt:@"Open"]; - - //convert wildcards - open panel only takes file extensions - - //no actual wildcards here :) - size_t lastwcpos = 0; - bool bDescription = true; - size_t i; - for(i = wildCard.find('|'); - i != wxString::npos; - i = wildCard.find('|', lastwcpos+1)) + types = nil; + bool useDefault = true; + for ( size_t i = 0; i < m_filterExtensions.GetCount(); ++i ) { - size_t oldi = i; - - if(!bDescription) + types = GetTypesFromExtension(m_filterExtensions[i], m_currentExtensions); + if ( m_currentExtensions.GetCount() == 0 ) { - bDescription = !bDescription; - - //work backwards looking for a period - while(i != lastwcpos && wildCard[--i] != '.') {} - - if(i == lastwcpos) + useDefault = false; + m_firstFileTypeFilter = i; + break; + } + + for ( size_t j = 0; j < m_currentExtensions.GetCount(); ++j ) + { + if ( m_fileName.EndsWith(m_currentExtensions[j]) ) { - //no extension - can't use this wildcard - lastwcpos = oldi; - continue; + m_firstFileTypeFilter = i; + useDefault = false; + break; } - - [m_wildcards addObject:wxNSStringWithWxString(wildCard.substr(i+1, oldi-i-1))]; } - else - bDescription = !bDescription; - lastwcpos = oldi; + if ( !useDefault ) + break; } - - if (!bDescription) + if ( useDefault ) { - //get last wildcard - size_t oldi = wildCard.length(); - i = oldi; + types = GetTypesFromExtension(m_filterExtensions[0], m_currentExtensions); + m_firstFileTypeFilter = 0; + } + } - //work backwards looking for a period - while(i != lastwcpos && wildCard[--i] != '.') {} + if ( HasFlag(wxFD_SAVE) ) + { + NSSavePanel* sPanel = [NSSavePanel savePanel]; - if(i != lastwcpos) - [m_wildcards addObject:wxNSStringWithWxString(wildCard.substr(i+1, oldi-i-1))]; - } + SetupExtraControls(sPanel); - if ([m_wildcards count] == 0) + // makes things more convenient: + [sPanel setCanCreateDirectories:YES]; + [sPanel setMessage:cf.AsNSString()]; + // if we should be able to descend into pacakges we must somehow + // be able to pass this in + [sPanel setTreatsFilePackagesAsDirectories:NO]; + [sPanel setCanSelectHiddenExtension:YES]; + [sPanel setAllowedFileTypes:types]; + [sPanel setAllowsOtherFileTypes:NO]; + + if ( HasFlag(wxFD_OVERWRITE_PROMPT) ) { - [m_wildcards release]; - m_wildcards = nil; } - } -} -wxFileDialog::~wxFileDialog() -{ - [m_wildcards release]; -} - -void wxFileDialog::GetPaths(wxArrayString& paths) const -{ - paths.Empty(); - - wxString dir(m_dir); - if ( m_dir.Last() != _T('\\') ) - dir += _T('\\'); + /* + Let the file dialog know what file type should be used initially. + If this is not done then when setting the filter index + programmatically to 1 the file will still have the extension + of the first file type instead of the second one. E.g. when file + types are foo and bar, a filename "myletter" with SetDialogIndex(1) + would result in saving as myletter.foo, while we want myletter.bar. + */ + if(m_firstFileTypeFilter > 0) + { + DoOnFilterSelected(m_firstFileTypeFilter); + } - size_t count = m_fileNames.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if (wxFileName(m_fileNames[n]).IsAbsolute()) - paths.Add(m_fileNames[n]); - else - paths.Add(dir + m_fileNames[n]); + returnCode = [sPanel runModalForDirectory: m_dir.IsEmpty() ? nil : dir.AsNSString() file:file.AsNSString() ]; + ModalFinishedCallback(sPanel, returnCode); } -} + else + { + NSOpenPanel* oPanel = [NSOpenPanel openPanel]; + + SetupExtraControls(oPanel); + + [oPanel setTreatsFilePackagesAsDirectories:NO]; + [oPanel setCanChooseDirectories:NO]; + [oPanel setResolvesAliases:YES]; + [oPanel setCanChooseFiles:YES]; + [oPanel setMessage:cf.AsNSString()]; + [oPanel setAllowsMultipleSelection: (HasFlag(wxFD_MULTIPLE) ? YES : NO )]; -void wxFileDialog::GetFilenames(wxArrayString& files) const -{ - files = m_fileNames; -} +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 + if ( UMAGetSystemVersion() >= 0x1060 && HasAppKit_10_6() ) + { + [oPanel setAllowedFileTypes: (m_delegate == nil ? types : nil)]; + if ( !m_dir.IsEmpty() ) + [oPanel setDirectoryURL:[NSURL fileURLWithPath:dir.AsNSString() + isDirectory:YES]]; + returnCode = [oPanel runModal]; + } + else +#endif + { + returnCode = [oPanel runModalForDirectory:m_dir.IsEmpty() ? nil : dir.AsNSString() + file:file.AsNSString() types:(m_delegate == nil ? types : nil)]; + } + + ModalFinishedCallback(oPanel, returnCode); + } -void wxFileDialog::SetPath(const wxString& path) -{ - wxString ext; - wxFileName::SplitPath(path, &m_dir, &m_fileName, &ext); - if ( !ext.empty() ) - m_fileName << _T('.') << ext; + return GetReturnCode(); } -int wxFileDialog::ShowModal() +void wxFileDialog::ModalFinishedCallback(void* panel, int returnCode) { - wxAutoNSAutoreleasePool thePool; - - m_fileNames.Empty(); - - int nResult; - + int result = wxID_CANCEL; if (HasFlag(wxFD_SAVE)) { - nResult = [GetNSSavePanel() - runModalForDirectory:wxNSStringWithWxString(m_dir) - file:wxNSStringWithWxString(m_fileName)]; - - if (nResult == NSOKButton) + if (returnCode == NSOKButton ) { - m_fileNames.Add(wxStringWithNSString([GetNSSavePanel() filename])); - m_path = m_fileNames[0]; + NSSavePanel* sPanel = (NSSavePanel*)panel; + result = wxID_OK; + + m_path = wxCFStringRef::AsStringWithNormalizationFormC([sPanel filename]); + m_fileName = wxFileNameFromPath(m_path); + m_dir = wxPathOnly( m_path ); + if (m_filterChoice) + { + m_filterIndex = m_filterChoice->GetSelection(); + } } } - else //m_dialogStyle & wxFD_OPEN + else { - nResult = [(NSOpenPanel*)m_cocoaNSWindow - runModalForDirectory:wxNSStringWithWxString(m_dir) - file:wxNSStringWithWxString(m_fileName) - types:m_wildcards]; - - if (nResult == NSOKButton) + NSOpenPanel* oPanel = (NSOpenPanel*)panel; + if (returnCode == NSOKButton ) { - for(unsigned i = 0; i < [[(NSOpenPanel*)m_cocoaNSWindow filenames] count]; ++i) + panel = oPanel; + result = wxID_OK; + NSArray* filenames = [oPanel filenames]; + for ( size_t i = 0 ; i < [filenames count] ; ++ i ) { - m_fileNames.Add(wxStringWithNSString([[(NSOpenPanel*)m_cocoaNSWindow filenames] objectAtIndex:(i)])); + wxString fnstr = wxCFStringRef::AsStringWithNormalizationFormC([filenames objectAtIndex:i]); + m_paths.Add( fnstr ); + m_fileNames.Add( wxFileNameFromPath(fnstr) ); + if ( i == 0 ) + { + m_path = fnstr; + m_fileName = wxFileNameFromPath(fnstr); + m_dir = wxPathOnly( fnstr ); + } } - - m_path = m_fileNames[0]; + } + if ( m_delegate ) + { + [oPanel setDelegate:nil]; + [m_delegate release]; + m_delegate = nil; } } - - return nResult == NSOKButton ? wxID_OK : wxID_CANCEL; + SetReturnCode(result); + + if (GetModality() == wxDIALOG_MODALITY_WINDOW_MODAL) + SendWindowModalDialogEvent ( wxEVT_WINDOW_MODAL_DIALOG_CLOSED ); + + // workaround for sandboxed app, see above + if ( m_isNativeWindowWrapper ) + UnsubclassWin(); + [(NSSavePanel*) panel setAccessoryView:nil]; } -#endif - #endif // wxUSE_FILEDLG