// Author: Ryan Norton
// Modified by:
// Created: 2004-10-02
-// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#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 <mach-o/dyld.h>
// ============================================================================
// implementation
// then the delegate method - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename will have to
// be implemented
+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
+
@interface wxOpenPanelDelegate : NSObject wxOSX_10_6_AND_LATER(<NSOpenSavePanelDelegate>)
{
wxFileDialog* _dialog;
- (id) init
{
- [super init];
+ self = [super init];
_dialog = NULL;
return self;
}
IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
-wxFileDialog::wxFileDialog(
+void wxFileDialog::Init()
+{
+ m_filterIndex = -1;
+ m_delegate = nil;
+ m_sheetDelegate = nil;
+}
+
+void wxFileDialog::Create(
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)
{
+ wxFileDialogBase::Create(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name);
+
+ m_sheetDelegate = [[ModalDialogDelegate alloc] init];
+ [(ModalDialogDelegate*)m_sheetDelegate setImplementation: this];
+}
+
+wxFileDialog::~wxFileDialog()
+{
+ [m_sheetDelegate release];
}
bool wxFileDialog::SupportsExtraControl() const
[sPanel setAllowsOtherFileTypes:NO];
NSWindow* nativeParent = parentWindow->GetWXWindow();
- ModalDialogDelegate* sheetDelegate = [[ModalDialogDelegate alloc] init];
- [sheetDelegate setImplementation: this];
[sPanel beginSheetForDirectory:dir.AsNSString() file:file.AsNSString()
- modalForWindow: nativeParent modalDelegate: sheetDelegate
+ modalForWindow: nativeParent modalDelegate: m_sheetDelegate
didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo: nil];
}
[oPanel setAllowsMultipleSelection: (HasFlag(wxFD_MULTIPLE) ? YES : NO )];
NSWindow* nativeParent = parentWindow->GetWXWindow();
- ModalDialogDelegate* sheetDelegate = [[ModalDialogDelegate alloc] init];
- [sheetDelegate setImplementation: this];
[oPanel beginSheetForDirectory:dir.AsNSString() file:file.AsNSString()
types: types modalForWindow: nativeParent
- modalDelegate: sheetDelegate
+ modalDelegate: m_sheetDelegate
didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo: nil];
}
if ( m_firstFileTypeFilter >= 0 )
m_filterChoice->SetSelection(m_firstFileTypeFilter);
}
- m_filterChoice->Connect(wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(wxFileDialog::OnFilterSelected), NULL, this);
+ m_filterChoice->Connect(wxEVT_CHOICE, wxCommandEventHandler(wxFileDialog::OnFilterSelected), NULL, this);
}
if(extracontrol)
return extrapanel;
}
-// An item has been selected in the file filter wxChoice:
-void wxFileDialog::OnFilterSelected( wxCommandEvent &WXUNUSED(event) )
+void wxFileDialog::DoOnFilterSelected(int index)
{
- int index = m_filterChoice->GetSelection();
-
NSArray* types = GetTypesFromExtension(m_filterExtensions[index],m_currentExtensions);
NSSavePanel* panel = (NSSavePanel*) GetWXWindow();
if ( m_delegate )
[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 )
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;
}
NSView* accView = nil;
- m_delegate = nil;
if ( m_useFileTypeFilter )
{
accView = m_filterPanel->GetHandle();
if( HasFlag(wxFD_OPEN) )
{
- if ( 1 /* UMAGetSystemVersion() < 0x1060 */ )
+ if ( UMAGetSystemVersion() < 0x1060 || !HasAppKit_10_6() )
{
wxOpenPanelDelegate* del = [[wxOpenPanelDelegate alloc]init];
[del setFileDialog:this];
int wxFileDialog::ShowModal()
{
+ WX_HOOK_MODAL_DIALOG();
+
+ wxCFEventLoopPauseIdleEvents pause;
+
+ wxMacAutoreleasePool autoreleasepool;
+
wxCFStringRef cf( m_message );
wxCFStringRef dir( m_dir );
m_path = wxEmptyString;
m_fileNames.Clear();
m_paths.Clear();
- // since we don't support retrieving the matching filter
- m_filterIndex = -1;
wxNonOwnedWindow* parentWindow = NULL;
int returnCode = -1;
}
m_firstFileTypeFilter = -1;
-
- if ( m_useFileTypeFilter )
+
+ if ( m_useFileTypeFilter
+ && m_filterIndex >= 0 && m_filterIndex < m_filterExtensions.GetCount() )
+ {
+ m_firstFileTypeFilter = m_filterIndex;
+ }
+ else if ( m_useFileTypeFilter )
{
types = nil;
bool useDefault = true;
{
}
- returnCode = [sPanel runModalForDirectory:dir.AsNSString() file:file.AsNSString() ];
+ /*
+ 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);
+ }
+
+ returnCode = [sPanel runModalForDirectory: m_dir.IsEmpty() ? nil : dir.AsNSString() file:file.AsNSString() ];
ModalFinishedCallback(sPanel, returnCode);
}
else
[oPanel setMessage:cf.AsNSString()];
[oPanel setAllowsMultipleSelection: (HasFlag(wxFD_MULTIPLE) ? YES : NO )];
- if ( UMAGetSystemVersion() < 0x1060 )
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ if ( UMAGetSystemVersion() >= 0x1060 && HasAppKit_10_6() )
{
- returnCode = [oPanel runModalForDirectory:dir.AsNSString()
- file:file.AsNSString() types:(m_delegate == nil ? types : nil)];
+ [oPanel setAllowedFileTypes: (m_delegate == nil ? types : nil)];
+ if ( !m_dir.IsEmpty() )
+ [oPanel setDirectoryURL:[NSURL fileURLWithPath:dir.AsNSString()
+ isDirectory:YES]];
+ returnCode = [oPanel runModal];
}
else
+#endif
{
- [oPanel setAllowedFileTypes: (m_delegate == nil ? types : nil)];
- [oPanel setDirectoryURL:[NSURL fileURLWithPath:dir.AsNSString()
- isDirectory:YES]];
- returnCode = [oPanel runModal];
+ returnCode = [oPanel runModalForDirectory:m_dir.IsEmpty() ? nil : dir.AsNSString()
+ file:file.AsNSString() types:(m_delegate == nil ? types : nil)];
}
-
+
ModalFinishedCallback(oPanel, returnCode);
}
NSSavePanel* sPanel = (NSSavePanel*)panel;
result = wxID_OK;
- m_path = wxCFStringRef::AsString([sPanel filename]);
+ m_path = wxCFStringRef::AsStringWithNormalizationFormC([sPanel filename]);
m_fileName = wxFileNameFromPath(m_path);
m_dir = wxPathOnly( m_path );
if (m_filterChoice)
NSArray* filenames = [oPanel filenames];
for ( size_t i = 0 ; i < [filenames count] ; ++ i )
{
- wxString fnstr = wxCFStringRef::AsString([filenames objectAtIndex:i]);
+ wxString fnstr = wxCFStringRef::AsStringWithNormalizationFormC([filenames objectAtIndex:i]);
m_paths.Add( fnstr );
m_fileNames.Add( wxFileNameFromPath(fnstr) );
if ( i == 0 )
if (GetModality() == wxDIALOG_MODALITY_WINDOW_MODAL)
SendWindowModalDialogEvent ( wxEVT_WINDOW_MODAL_DIALOG_CLOSED );
- UnsubclassWin();
+ // workaround for sandboxed app, see above
+ if ( m_isNativeWindowWrapper )
+ UnsubclassWin();
[(NSSavePanel*) panel setAccessoryView:nil];
}