s/wxSplitPath/wxFileName::SplitPath
[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
34 #include "wx/osx/private.h"
35
36 // ============================================================================
37 // implementation
38 // ============================================================================
39
40 IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
41
42 wxFileDialog::wxFileDialog(
43     wxWindow *parent, const wxString& message,
44     const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard,
45     long style, const wxPoint& pos, const wxSize& sz, const wxString& name)
46     : wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name)
47 {
48 }
49
50
51 NSArray* GetTypesFromFilter( const wxString filter )
52 {
53     NSMutableArray* types = nil;
54     if ( !filter.empty() )
55     {
56         wxArrayString names ;
57         wxArrayString extensions;
58
59         wxString filter2(filter) ;
60         int filterIndex = 0;
61         bool isName = true ;
62         wxString current ;
63
64         for ( unsigned int i = 0; i < filter2.length() ; i++ )
65         {
66             if ( filter2.GetChar(i) == wxT('|') )
67             {
68                 if ( isName )
69                 {
70                     names.Add( current ) ;
71                 }
72                 else
73                 {
74                     extensions.Add( current ) ;
75                     ++filterIndex ;
76                 }
77
78                 isName = !isName ;
79                 current = wxEmptyString ;
80             }
81             else
82             {
83                 current += filter2.GetChar(i) ;
84             }
85         }
86         // we allow for compatibility reason to have a single filter expression (like *.*) without
87         // an explanatory text, in that case the first part is name and extension at the same time
88
89         wxASSERT_MSG( filterIndex == 0 || !isName , wxT("incorrect format of format string") ) ;
90         if ( current.empty() )
91             extensions.Add( names[filterIndex] ) ;
92         else
93             extensions.Add( current ) ;
94         if ( filterIndex == 0 || isName )
95             names.Add( current ) ;
96
97         ++filterIndex ;
98
99         const size_t extCount = extensions.GetCount();
100         for ( size_t i = 0 ; i < extCount; i++ )
101         {
102             wxString extension = extensions[i];
103
104             // Remove leading '*'
105             if (extension.length() && (extension.GetChar(0) == '*'))
106                 extension = extension.Mid( 1 );
107
108             // Remove leading '.'
109             if (extension.length() && (extension.GetChar(0) == '.'))
110                 extension = extension.Mid( 1 );
111
112             if ( extension.IsEmpty() )
113             {
114                 if ( types != nil )
115                     [types release];
116                 return nil;
117             }
118
119
120             if ( types == nil )
121                 types = [[NSMutableArray alloc] init];
122
123             wxCFStringRef cfext(extension);
124             [types addObject: (NSString*)cfext.AsNSString()  ];
125 #if 0
126             wxUint32 fileType, creator;
127
128             // extension -> mactypes
129 #endif
130         }
131     }
132     return types;
133 }
134
135 int wxFileDialog::ShowModal()
136 {
137     int result = wxID_CANCEL;
138
139     NSSavePanel *panel = nil;
140
141     wxCFStringRef cf( m_message );
142
143     wxCFStringRef dir( m_path );
144     wxCFStringRef file( m_fileName );
145
146     m_path = wxEmptyString;
147     m_fileNames.Clear();
148
149     if (HasFlag(wxFD_SAVE))
150     {
151         NSSavePanel* sPanel = [NSSavePanel savePanel];
152         // makes things more convenient:
153         [sPanel setCanCreateDirectories:YES];
154         [sPanel setMessage:cf.AsNSString()];
155         [sPanel setTreatsFilePackagesAsDirectories:NO];
156
157         if ( HasFlag(wxFD_OVERWRITE_PROMPT) )
158         {
159         }
160
161         if ( [sPanel runModalForDirectory:dir.AsNSString() file:file.AsNSString() ] == NSOKButton )
162         {
163             panel = sPanel;
164             result = wxID_OK;
165
166             wxCFStringRef filename( [[sPanel filename] retain] );
167
168             m_path = filename.AsString();
169             m_fileName = wxFileNameFromPath(m_path);
170             m_dir = wxPathOnly( m_path );
171         }
172     }
173     else
174     {
175         NSArray* types = GetTypesFromFilter( m_wildCard ) ;
176         NSOpenPanel* oPanel = [NSOpenPanel openPanel];
177         [oPanel setTreatsFilePackagesAsDirectories:NO];
178         [oPanel setCanChooseDirectories:NO];
179         [oPanel setResolvesAliases:YES];
180         [oPanel setCanChooseFiles:YES];
181         [oPanel setMessage:cf.AsNSString()];
182
183         if ( [oPanel runModalForDirectory:dir.AsNSString() file:file.AsNSString() types:types] == NSOKButton )
184         {
185             panel = oPanel;
186             result = wxID_OK;
187             NSArray* filenames = [oPanel filenames];
188             for ( size_t i = 0 ; i < [filenames count] ; ++ i )
189             {
190                 wxCFStringRef filename( [(NSString*) [filenames objectAtIndex:i] retain] );
191                 wxString fnstr = filename.AsString();
192                 m_paths.Add( fnstr );
193                 m_fileNames.Add( wxFileNameFromPath(fnstr) );
194                 if ( i == 0 )
195                 {
196                     m_path = fnstr;
197                     m_fileName = wxFileNameFromPath(fnstr);
198                     m_dir = wxPathOnly( fnstr );
199                 }
200             }
201         }
202         if ( types != nil )
203             [types release];
204     }
205
206     return result;
207 }
208
209 #if 0
210
211     wxASSERT(CreateBase(parent,wxID_ANY,pos,wxDefaultSize,style,wxDefaultValidator,wxDialogNameStr));
212
213     if ( parent )
214         parent->AddChild(this);
215
216     m_cocoaNSWindow = nil;
217     m_cocoaNSView = nil;
218
219     //Init the wildcard array
220     m_wildcards = [[NSMutableArray alloc] initWithCapacity:0];
221
222     //If the user requests to save - use a NSSavePanel
223     //else use a NSOpenPanel
224     if (HasFlag(wxFD_SAVE))
225     {
226         SetNSPanel([NSSavePanel savePanel]);
227
228         [GetNSSavePanel() setTitle:wxNSStringWithWxString(message)];
229
230         [GetNSSavePanel() setPrompt:@"Save"];
231         [GetNSSavePanel() setTreatsFilePackagesAsDirectories:YES];
232         [GetNSSavePanel() setCanSelectHiddenExtension:YES];
233
234 //        Cached as per-app in obj-c
235 //        [GetNSSavePanel() setExtensionHidden:YES];
236
237         //
238         // NB:  Note that only Panther supports wildcards
239         // with save dialogs - not that wildcards in save
240         // dialogs are all that useful, anyway :)
241         //
242     }
243     else //m_dialogStyle & wxFD_OPEN
244     {
245         SetNSPanel([NSOpenPanel openPanel]);
246         [m_cocoaNSWindow setTitle:wxNSStringWithWxString(message)];
247
248         [(NSOpenPanel*)m_cocoaNSWindow setAllowsMultipleSelection:(HasFlag(wxFD_MULTIPLE))];
249         [(NSOpenPanel*)m_cocoaNSWindow setResolvesAliases:YES];
250         [(NSOpenPanel*)m_cocoaNSWindow setCanChooseFiles:YES];
251         [(NSOpenPanel*)m_cocoaNSWindow setCanChooseDirectories:NO];
252         [GetNSSavePanel() setPrompt:@"Open"];
253
254         //convert wildcards - open panel only takes file extensions -
255         //no actual wildcards here :)
256         size_t lastwcpos = 0;
257         bool bDescription = true;
258         size_t i;
259         for(i = wildCard.find('|');
260                 i != wxString::npos;
261                 i = wildCard.find('|', lastwcpos+1))
262         {
263             size_t oldi = i;
264
265             if(!bDescription)
266             {
267                 bDescription = !bDescription;
268
269                 //work backwards looking for a period
270                 while(i != lastwcpos && wildCard[--i] != '.') {}
271
272                 if(i == lastwcpos)
273                 {
274                     //no extension - can't use this wildcard
275                     lastwcpos = oldi;
276                     continue;
277                 }
278
279                 [m_wildcards addObject:wxNSStringWithWxString(wildCard.substr(i+1, oldi-i-1))];
280             }
281             else
282                 bDescription = !bDescription;
283             lastwcpos = oldi;
284         }
285
286         if (!bDescription)
287         {
288             //get last wildcard
289             size_t oldi = wildCard.length();
290             i = oldi;
291
292             //work backwards looking for a period
293             while(i != lastwcpos && wildCard[--i] != '.') {}
294
295             if(i != lastwcpos)
296                 [m_wildcards addObject:wxNSStringWithWxString(wildCard.substr(i+1, oldi-i-1))];
297         }
298
299         if ([m_wildcards count] == 0)
300         {
301             [m_wildcards release];
302             m_wildcards = nil;
303         }
304     }
305 }
306
307 wxFileDialog::~wxFileDialog()
308 {
309     [m_wildcards release];
310 }
311
312 void wxFileDialog::GetPaths(wxArrayString& paths) const
313 {
314     paths.Empty();
315
316     wxString dir(m_dir);
317     if ( m_dir.Last() != _T('\\') )
318         dir += _T('\\');
319
320     size_t count = m_fileNames.GetCount();
321     for ( size_t n = 0; n < count; n++ )
322     {
323         if (wxFileName(m_fileNames[n]).IsAbsolute())
324             paths.Add(m_fileNames[n]);
325         else
326             paths.Add(dir + m_fileNames[n]);
327     }
328 }
329
330 void wxFileDialog::GetFilenames(wxArrayString& files) const
331 {
332     files = m_fileNames;
333 }
334
335 void wxFileDialog::SetPath(const wxString& path)
336 {
337     wxString ext;
338     wxFileName::SplitPath(path, &m_dir, &m_fileName, &ext);
339     if ( !ext.empty() )
340         m_fileName << _T('.') << ext;
341 }
342
343 int wxFileDialog::ShowModal()
344 {
345     wxAutoNSAutoreleasePool thePool;
346
347     m_fileNames.Empty();
348
349     int nResult;
350
351     if (HasFlag(wxFD_SAVE))
352     {
353         nResult = [GetNSSavePanel()
354                     runModalForDirectory:wxNSStringWithWxString(m_dir)
355                     file:wxNSStringWithWxString(m_fileName)];
356
357         if (nResult == NSOKButton)
358         {
359             m_fileNames.Add(wxStringWithNSString([GetNSSavePanel() filename]));
360             m_path = m_fileNames[0];
361         }
362     }
363     else //m_dialogStyle & wxFD_OPEN
364     {
365         nResult = [(NSOpenPanel*)m_cocoaNSWindow
366                     runModalForDirectory:wxNSStringWithWxString(m_dir)
367                     file:wxNSStringWithWxString(m_fileName)
368                     types:m_wildcards];
369
370         if (nResult == NSOKButton)
371         {
372             for(unsigned i = 0; i < [[(NSOpenPanel*)m_cocoaNSWindow filenames] count]; ++i)
373             {
374                 m_fileNames.Add(wxStringWithNSString([[(NSOpenPanel*)m_cocoaNSWindow filenames] objectAtIndex:(i)]));
375             }
376
377             m_path = m_fileNames[0];
378         }
379     }
380
381     return nResult == NSOKButton ? wxID_OK : wxID_CANCEL;
382 }
383
384 #endif
385
386 #endif // wxUSE_FILEDLG