]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/filedlg.mm
19c84eee0aa81c7c58d896aeee0fb6acc9d03a02
[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