conforming to deprecation recommendation for 10.6
[wxWidgets.git] / src / osx / cocoa / filedlg.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/filedlg.mm
3 // Purpose:     wxFileDialog for wxCocoa
4 // Author:      Ryan Norton
5 // Modified by:
6 // Created:     2004-10-02
7 // RCS-ID:      $Id: filedlg.mm 40007 2006-07-05 13:10:46Z SC $
8 // Copyright:   (c) Ryan Norton
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #if wxUSE_FILEDLG
24
25 #include "wx/filedlg.h"
26
27 #ifndef WX_PRECOMP
28     #include "wx/msgdlg.h"
29     #include "wx/app.h"
30 #endif
31
32 #include "wx/filename.h"
33 #include "wx/tokenzr.h"
34
35 #include "wx/osx/private.h"
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // Open Items:
42 // - support for old style MacOS creator / type combos
43 // - parameter support for descending into packages as directories (setTreatsFilePackagesAsDirectories)
44
45 IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
46
47 wxFileDialog::wxFileDialog(
48     wxWindow *parent, const wxString& message,
49     const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard,
50     long style, const wxPoint& pos, const wxSize& sz, const wxString& name)
51     : wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name)
52 {
53 }
54
55 bool wxFileDialog::SupportsExtraControl() const
56 {
57     return true;
58 }
59
60 NSArray* CopyTypesFromFilter( const wxString filter )
61 {
62     NSMutableArray* types = nil;
63     if ( !filter.empty() )
64     {
65         wxArrayString names ;
66         wxArrayString extensions;
67
68         wxString filter2(filter) ;
69         int filterIndex = 0;
70         bool isName = true ;
71         wxString current ;
72
73         for ( unsigned int i = 0; i < filter2.length() ; i++ )
74         {
75             if ( filter2.GetChar(i) == wxT('|') )
76             {
77                 if ( isName )
78                 {
79                     names.Add( current ) ;
80                 }
81                 else
82                 {
83                     extensions.Add( current ) ;
84                     ++filterIndex ;
85                 }
86
87                 isName = !isName ;
88                 current = wxEmptyString ;
89             }
90             else
91             {
92                 current += filter2.GetChar(i) ;
93             }
94         }
95         // we allow for compatibility reason to have a single filter expression (like *.*) without
96         // an explanatory text, in that case the first part is name and extension at the same time
97
98         wxASSERT_MSG( filterIndex == 0 || !isName , wxT("incorrect format of format string") ) ;
99         if ( current.empty() )
100             extensions.Add( names[filterIndex] ) ;
101         else
102             extensions.Add( current ) ;
103         if ( filterIndex == 0 || isName )
104             names.Add( current ) ;
105
106         ++filterIndex ;
107
108         const size_t extCount = extensions.GetCount();
109         for ( size_t i = 0 ; i < extCount; i++ )
110         {
111             wxString extensiongroup = extensions[i];
112             wxStringTokenizer tokenizer( extensiongroup , wxT(";") ) ;
113             while ( tokenizer.HasMoreTokens() )
114             {
115                 wxString extension = tokenizer.GetNextToken() ;
116                 // Remove leading '*'
117                 if (extension.length() && (extension.GetChar(0) == '*'))
118                     extension = extension.Mid( 1 );
119
120                 // Remove leading '.'
121                 if (extension.length() && (extension.GetChar(0) == '.'))
122                     extension = extension.Mid( 1 );
123
124                 // Remove leading '*', this is for handling *.*
125                 if (extension.length() && (extension.GetChar(0) == '*'))
126                     extension = extension.Mid( 1 );
127
128                 if ( extension.IsEmpty() )
129                 {
130                     [types release];
131                     types = nil;
132                     return nil;
133                 }
134
135                 if ( types == nil )
136                     types = [[NSMutableArray alloc] init];
137
138                 wxCFStringRef cfext(extension);
139                 [types addObject: (NSString*)cfext.AsNSString()  ];
140 #if 0
141                 // add support for classic fileType / creator here
142                 wxUint32 fileType, creator;
143                 // extension -> mactypes
144 #endif
145             }
146
147         }
148     }
149     return types;
150 }
151
152 void wxFileDialog::ShowWindowModal()
153 {
154     wxCFStringRef cf( m_message );
155     wxCFStringRef dir( m_dir );
156     wxCFStringRef file( m_fileName );
157
158     wxNonOwnedWindow* parentWindow = NULL;
159     
160     m_modality = wxDIALOG_MODALITY_WINDOW_MODAL;
161
162     if (GetParent())
163         parentWindow = dynamic_cast<wxNonOwnedWindow*>(wxGetTopLevelParent(GetParent()));
164
165     wxASSERT_MSG(parentWindow, "Window modal display requires parent.");
166     
167     NSArray* types = CopyTypesFromFilter( m_wildCard ) ;
168     if (HasFlag(wxFD_SAVE))
169     {
170         NSSavePanel* sPanel = [NSSavePanel savePanel];
171
172         SetupExtraControls(sPanel);
173
174         // makes things more convenient:
175         [sPanel setCanCreateDirectories:YES];
176         [sPanel setMessage:cf.AsNSString()];
177         // if we should be able to descend into pacakges we must somehow
178         // be able to pass this in
179         [sPanel setTreatsFilePackagesAsDirectories:NO];
180         [sPanel setCanSelectHiddenExtension:YES];
181         [sPanel setAllowedFileTypes:types];
182         [sPanel setAllowsOtherFileTypes:NO];
183         
184         NSWindow* nativeParent = parentWindow->GetWXWindow();
185         ModalDialogDelegate* sheetDelegate = [[ModalDialogDelegate alloc] init];
186         [sheetDelegate setImplementation: this];
187         [sPanel beginSheetForDirectory:dir.AsNSString() file:file.AsNSString()
188             modalForWindow: nativeParent modalDelegate: sheetDelegate
189             didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
190             contextInfo: nil];
191     }
192     else 
193     {
194         NSOpenPanel* oPanel = [NSOpenPanel openPanel];
195         
196         SetupExtraControls(oPanel);
197
198         [oPanel setTreatsFilePackagesAsDirectories:NO];
199         [oPanel setCanChooseDirectories:NO];
200         [oPanel setResolvesAliases:YES];
201         [oPanel setCanChooseFiles:YES];
202         [oPanel setMessage:cf.AsNSString()];
203         [oPanel setAllowsMultipleSelection: (HasFlag(wxFD_MULTIPLE) ? YES : NO )];
204         
205         NSWindow* nativeParent = parentWindow->GetWXWindow();
206         ModalDialogDelegate* sheetDelegate = [[ModalDialogDelegate alloc] init];
207         [sheetDelegate setImplementation: this];
208         [oPanel beginSheetForDirectory:dir.AsNSString() file:file.AsNSString()
209             types: types modalForWindow: nativeParent
210             modalDelegate: sheetDelegate
211             didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
212             contextInfo: nil];
213     }
214     [types release];
215     types = nil;
216 }
217
218 void wxFileDialog::SetupExtraControls(WXWindow nativeWindow)
219 {
220     NSSavePanel* panel = (NSSavePanel*) nativeWindow;
221     
222     wxNonOwnedWindow::Create( GetParent(), nativeWindow );
223     
224     if (HasExtraControlCreator())
225     {
226         CreateExtraControl();
227         wxWindow* control = GetExtraControl();
228         if ( control )
229         {
230             NSView* accView = control->GetHandle();
231             [accView removeFromSuperview];
232             [panel setAccessoryView:accView];
233         }
234         else
235         {
236             [panel setAccessoryView:nil];
237         }
238     }
239 }
240
241 int wxFileDialog::ShowModal()
242 {
243     wxCFStringRef cf( m_message );
244
245     wxCFStringRef dir( m_dir );
246     wxCFStringRef file( m_fileName );
247
248     m_path = wxEmptyString;
249     m_fileNames.Clear();
250     m_paths.Clear();
251     // since we don't support retrieving the matching filter
252     m_filterIndex = -1;
253
254     wxNonOwnedWindow* parentWindow = NULL;
255     int returnCode = -1;
256
257     if (GetParent())
258     {
259         parentWindow = dynamic_cast<wxNonOwnedWindow*>(wxGetTopLevelParent(GetParent()));
260     }
261
262     NSArray* types = CopyTypesFromFilter( m_wildCard ) ;
263     if (HasFlag(wxFD_SAVE))
264     {
265         NSSavePanel* sPanel = [NSSavePanel savePanel];
266
267         SetupExtraControls(sPanel);
268
269         // makes things more convenient:
270         [sPanel setCanCreateDirectories:YES];
271         [sPanel setMessage:cf.AsNSString()];
272         // if we should be able to descend into pacakges we must somehow
273         // be able to pass this in
274         [sPanel setTreatsFilePackagesAsDirectories:NO];
275         [sPanel setCanSelectHiddenExtension:YES];
276         [sPanel setAllowedFileTypes:types];
277         [sPanel setAllowsOtherFileTypes:NO];
278
279         if ( HasFlag(wxFD_OVERWRITE_PROMPT) )
280         {
281         }
282
283         returnCode = [sPanel runModalForDirectory:dir.AsNSString() file:file.AsNSString() ];
284         ModalFinishedCallback(sPanel, returnCode);
285
286         UnsubclassWin();
287         [sPanel setAccessoryView:nil];
288     }
289     else
290     {
291         NSOpenPanel* oPanel = [NSOpenPanel openPanel];
292         
293         SetupExtraControls(oPanel);
294                 
295         [oPanel setTreatsFilePackagesAsDirectories:NO];
296         [oPanel setCanChooseDirectories:NO];
297         [oPanel setResolvesAliases:YES];
298         [oPanel setCanChooseFiles:YES];
299         [oPanel setMessage:cf.AsNSString()];
300         [oPanel setAllowsMultipleSelection: (HasFlag(wxFD_MULTIPLE) ? YES : NO )];
301
302         if ( UMAGetSystemVersion() < 0x1060 )
303         {
304             returnCode = [oPanel runModalForDirectory:dir.AsNSString()
305                         file:file.AsNSString() types:types];
306         }
307         else 
308         {
309             [oPanel setAllowedFileTypes:types];
310             [oPanel setDirectoryURL:[NSURL fileURLWithPath:dir.AsNSString() 
311                                                isDirectory:YES]];
312             returnCode = [oPanel runModal];
313         }
314
315         ModalFinishedCallback(oPanel, returnCode);
316         
317         UnsubclassWin();
318         [oPanel setAccessoryView:nil];
319         
320     }
321     [types release];
322     types = nil;
323
324     return GetReturnCode();
325 }
326
327 void wxFileDialog::ModalFinishedCallback(void* panel, int returnCode)
328 {
329     int result = wxID_CANCEL;
330     if (HasFlag(wxFD_SAVE))
331     {
332         if (returnCode == NSOKButton )
333         {
334             NSSavePanel* sPanel = (NSSavePanel*)panel;
335             result = wxID_OK;
336
337             m_path = wxCFStringRef::AsString([sPanel filename]);
338             m_fileName = wxFileNameFromPath(m_path);
339             m_dir = wxPathOnly( m_path );
340         }
341     }
342     else
343     {
344         NSOpenPanel* oPanel = (NSOpenPanel*)panel;
345         if (returnCode == NSOKButton )
346         {
347             panel = oPanel;
348             result = wxID_OK;
349             NSArray* filenames = [oPanel filenames];
350             for ( size_t i = 0 ; i < [filenames count] ; ++ i )
351             {
352                 wxString fnstr = wxCFStringRef::AsString([filenames objectAtIndex:i]);
353                 m_paths.Add( fnstr );
354                 m_fileNames.Add( wxFileNameFromPath(fnstr) );
355                 if ( i == 0 )
356                 {
357                     m_path = fnstr;
358                     m_fileName = wxFileNameFromPath(fnstr);
359                     m_dir = wxPathOnly( fnstr );
360                 }
361             }
362         }
363     }
364     SetReturnCode(result);
365     
366     if (GetModality() == wxDIALOG_MODALITY_WINDOW_MODAL)
367         SendWindowModalDialogEvent ( wxEVT_WINDOW_MODAL_DIALOG_CLOSED  );
368     
369     [(NSSavePanel*) panel setAccessoryView:nil];
370 }
371
372 #endif // wxUSE_FILEDLG