]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/filedlg.cpp
Corrected accidental pointer arithmetic in ClientToScreen and vice versa
[wxWidgets.git] / src / mac / carbon / filedlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: filedlg.cpp
3 // Purpose: wxFileDialog
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "filedlg.h"
14 #endif
15
16 #include "wx/defs.h"
17 #include "wx/app.h"
18 #include "wx/utils.h"
19 #include "wx/dialog.h"
20 #include "wx/filedlg.h"
21 #include "wx/intl.h"
22 #include "wx/tokenzr.h"
23
24 #ifndef __DARWIN__
25 #include "PLStringFuncs.h"
26 #endif
27
28 #if !USE_SHARED_LIBRARY
29 IMPLEMENT_CLASS(wxFileDialog, wxDialog)
30 #endif
31
32 // begin wxmac
33
34 #include "wx/mac/private.h"
35
36 #include <Navigation.h>
37
38 #include "MoreFiles.h"
39 #include "MoreFilesExtras.h"
40
41 extern bool gUseNavServices ;
42
43 // the data we need to pass to our standard file hook routine
44 // includes a pointer to the dialog, a pointer to the standard
45 // file reply record (so we can inspect the current selection)
46 // and a copy of the "previous" file spec of the reply record
47 // so we can see if the selection has changed
48
49 struct OpenUserDataRec {
50 int currentfilter ;
51 bool saveMode ;
52 wxArrayString name ;
53 wxArrayString extensions ;
54 wxArrayLong filtermactypes ;
55 NavMenuItemSpecArrayHandle menuitems ;
56 };
57
58 typedef struct OpenUserDataRec
59 OpenUserDataRec, *OpenUserDataRecPtr;
60
61 static pascal void NavEventProc(
62 NavEventCallbackMessage inSelector,
63 NavCBRecPtr ioParams,
64 NavCallBackUserData ioUserData);
65
66 #if TARGET_CARBON
67 static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc);
68 #else
69 static NavEventUPP sStandardNavEventFilter = NewNavEventProc(NavEventProc);
70 #endif
71
72 static pascal void
73 NavEventProc(
74 NavEventCallbackMessage inSelector,
75 NavCBRecPtr ioParams,
76 NavCallBackUserData ioUserData )
77 {
78 OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ;
79 if (inSelector == kNavCBEvent) {
80 wxTheApp->MacHandleOneEvent(ioParams->eventData.eventDataParms.event);
81 }
82 else if ( inSelector == kNavCBStart )
83 {
84 if ( data->menuitems )
85 NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &(*data->menuitems)[data->currentfilter]);
86 }
87 else if ( inSelector == kNavCBPopupMenuSelect )
88 {
89 NavMenuItemSpec * menu = (NavMenuItemSpec *) ioParams->eventData.eventDataParms.param ;
90 if ( menu->menuCreator == 'WXNG' )
91 {
92 data->currentfilter = menu->menuType ;
93 if ( data->saveMode )
94 {
95 int i = menu->menuType ;
96 wxString extension = data->extensions[i].AfterLast('.') ;
97 extension.MakeLower() ;
98 Str255 filename ;
99 // get the current filename
100 NavCustomControl(ioParams->context, kNavCtlGetEditFileName, &filename);
101 CopyPascalStringToC( filename , (char*) filename ) ;
102 wxString sfilename( filename ) ;
103 int pos = sfilename.Find('.',TRUE) ;
104 if ( pos != wxNOT_FOUND )
105 {
106 sfilename = sfilename.Left(pos+1)+extension ;
107 CopyCStringToPascal( sfilename.c_str() , filename ) ;
108 NavCustomControl(ioParams->context, kNavCtlSetEditFileName, &filename);
109 }
110 }
111 }
112 }
113 }
114
115 const char * gfilters[] =
116 {
117 "*.TXT" ,
118 "*.TIF" ,
119 "*.JPG" ,
120
121 NULL
122 } ;
123
124 OSType gfiltersmac[] =
125 {
126 'TEXT' ,
127 'TIFF' ,
128 'JPEG' ,
129
130 '****'
131 } ;
132
133
134
135 void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter )
136 {
137 myData->menuitems = NULL ;
138 myData->currentfilter = 0 ;
139 myData->saveMode = FALSE ;
140
141 if ( filter && filter[0] )
142 {
143 wxString filter2(filter) ;
144 int filterIndex = 0;
145 bool isName = true ;
146 wxString current ;
147 for( unsigned int i = 0; i < filter2.Len() ; i++ )
148 {
149 if( filter2.GetChar(i) == wxT('|') )
150 {
151 if( isName ) {
152 myData->name.Add( current ) ;
153 }
154 else {
155 myData->extensions.Add( current.MakeUpper() ) ;
156 ++filterIndex ;
157 }
158 isName = !isName ;
159 current = "" ;
160 }
161 else
162 {
163 current += filter2.GetChar(i) ;
164 }
165 }
166 // we allow for compatibility reason to have a single filter expression (like *.*) without
167 // an explanatory text, in that case the first part is name and extension at the same time
168
169 wxASSERT_MSG( filterIndex == 0 || !isName , "incorrect format of format string" ) ;
170 if ( current.IsEmpty() )
171 myData->extensions.Add( myData->name[filterIndex] ) ;
172 else
173 myData->extensions.Add( current.MakeUpper() ) ;
174 if ( filterIndex == 0 || isName )
175 myData->name.Add( current.MakeUpper() ) ;
176
177 ++filterIndex ;
178
179
180 const size_t extCount = myData->extensions.GetCount();
181 for ( size_t i = 0 ; i < extCount; i++ )
182 {
183 int j ;
184 for ( j = 0 ; gfilters[j] ; j++ )
185 {
186 if ( strcmp( myData->extensions[i] , gfilters[j] ) == 0 )
187 {
188 myData->filtermactypes.Add( gfiltersmac[j] ) ;
189 break ;
190 }
191 }
192 if( gfilters[j] == NULL )
193 {
194 myData->filtermactypes.Add( '****' ) ;
195 }
196 }
197 }
198 }
199
200 static Boolean CheckFile( ConstStr255Param name , OSType type , OpenUserDataRecPtr data)
201 {
202 Str255 filename ;
203
204 #if TARGET_CARBON
205 p2cstrcpy((char *)filename, name) ;
206 #else
207 PLstrcpy( filename , name ) ;
208 p2cstr( filename ) ;
209 #endif
210 wxString file(filename) ;
211 file.MakeUpper() ;
212
213 if ( data->extensions.GetCount() > 0 )
214 {
215 //for ( int i = 0 ; i < data->numfilters ; ++i )
216 int i = data->currentfilter ;
217 if ( data->extensions[i].Right(2) == ".*" )
218 return true ;
219
220 {
221 if ( type == (OSType)data->filtermactypes[i] )
222 return true ;
223
224 wxStringTokenizer tokenizer( data->extensions[i] , ";" ) ;
225 while( tokenizer.HasMoreTokens() )
226 {
227 wxString extension = tokenizer.GetNextToken() ;
228 if ( extension.GetChar(0) == '*' )
229 extension = extension.Mid(1) ;
230
231 if ( file.Len() >= extension.Len() && extension == file.Right(extension.Len() ) )
232 return true ;
233 }
234 }
235 return false ;
236 }
237 return true ;
238 }
239
240 #ifndef __DARWIN__
241 static pascal Boolean CrossPlatformFileFilter(CInfoPBPtr myCInfoPBPtr, void *dataPtr)
242 {
243 OpenUserDataRecPtr data = (OpenUserDataRecPtr) dataPtr ;
244 // return true if this item is invisible or a file
245
246 Boolean visibleFlag;
247 Boolean folderFlag;
248
249 visibleFlag = ! (myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible);
250 folderFlag = (myCInfoPBPtr->hFileInfo.ioFlAttrib & 0x10);
251
252 // because the semantics of the filter proc are "true means don't show
253 // it" we need to invert the result that we return
254
255 if ( !visibleFlag )
256 return true ;
257
258 if ( !folderFlag )
259 {
260 return !CheckFile( myCInfoPBPtr->hFileInfo.ioNamePtr , myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType , data ) ;
261 }
262
263 return false ;
264 }
265 #endif
266
267 // end wxmac
268
269 wxString wxFileSelector(const char *title,
270 const char *defaultDir, const char *defaultFileName,
271 const char *defaultExtension, const char *filter, int flags,
272 wxWindow *parent, int x, int y)
273 {
274 // If there's a default extension specified but no filter, we create a suitable
275 // filter.
276
277 wxString filter2("");
278 if ( defaultExtension && !filter )
279 filter2 = wxString("*.") + wxString(defaultExtension) ;
280 else if ( filter )
281 filter2 = filter;
282
283 wxString defaultDirString;
284 if (defaultDir)
285 defaultDirString = defaultDir;
286 else
287 defaultDirString = "";
288
289 wxString defaultFilenameString;
290 if (defaultFileName)
291 defaultFilenameString = defaultFileName;
292 else
293 defaultFilenameString = "";
294
295 wxFileDialog fileDialog(parent, title, defaultDirString, defaultFilenameString, filter2, flags, wxPoint(x, y));
296
297 if ( fileDialog.ShowModal() == wxID_OK )
298 {
299 strcpy(wxBuffer, (const char *)fileDialog.GetPath());
300 return wxBuffer;
301 }
302 else
303 return wxGetEmptyString();
304 }
305
306 WXDLLEXPORT wxString wxFileSelectorEx(const char *title,
307 const char *defaultDir,
308 const char *defaultFileName,
309 int* defaultFilterIndex,
310 const char *filter,
311 int flags,
312 wxWindow* parent,
313 int x,
314 int y)
315
316 {
317 wxFileDialog fileDialog(parent, title ? title : "", defaultDir ? defaultDir : "",
318 defaultFileName ? defaultFileName : "", filter ? filter : "", flags, wxPoint(x, y));
319
320 if ( fileDialog.ShowModal() == wxID_OK )
321 {
322 *defaultFilterIndex = fileDialog.GetFilterIndex();
323 strcpy(wxBuffer, (const char *)fileDialog.GetPath());
324 return wxBuffer;
325 }
326 else
327 return wxGetEmptyString();
328 }
329
330 wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message,
331 const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard,
332 long style, const wxPoint& pos)
333 {
334 wxASSERT_MSG( NavServicesAvailable() , "Navigation Services are not running" ) ;
335 m_message = message;
336 m_dialogStyle = style;
337 m_parent = parent;
338 m_path = "";
339 m_fileName = defaultFileName;
340 m_dir = defaultDir;
341 m_wildCard = wildCard;
342 m_filterIndex = 0;
343 }
344
345
346 pascal Boolean CrossPlatformFilterCallback (
347 AEDesc *theItem,
348 void *info,
349 void *callBackUD,
350 NavFilterModes filterMode
351 )
352 {
353 bool display = true;
354 OpenUserDataRecPtr data = (OpenUserDataRecPtr) callBackUD ;
355
356 if (filterMode == kNavFilteringBrowserList)
357 {
358 NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*) info ;
359 if (theItem->descriptorType == typeFSS && !theInfo->isFolder)
360 {
361 FSSpec spec;
362 memcpy( &spec , *theItem->dataHandle , sizeof(FSSpec) ) ;
363 display = CheckFile( spec.name , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ;
364 }
365 }
366
367 return display;
368 }
369
370 int wxFileDialog::ShowModal()
371 {
372 NavDialogOptions mNavOptions;
373 NavObjectFilterUPP mNavFilterUPP = NULL;
374 NavPreviewUPP mNavPreviewUPP = NULL ;
375 NavReplyRecord mNavReply;
376 AEDesc mDefaultLocation ;
377 bool mSelectDefault = false ;
378
379 ::NavGetDefaultDialogOptions(&mNavOptions);
380
381 mNavFilterUPP = nil;
382 mNavPreviewUPP = nil;
383 mSelectDefault = false;
384 mNavReply.validRecord = false;
385 mNavReply.replacing = false;
386 mNavReply.isStationery = false;
387 mNavReply.translationNeeded = false;
388 mNavReply.selection.descriptorType = typeNull;
389 mNavReply.selection.dataHandle = nil;
390 mNavReply.keyScript = smSystemScript;
391 mNavReply.fileTranslation = nil;
392
393 // Set default location, the location
394 // that's displayed when the dialog
395 // first appears
396
397 FSSpec location ;
398 wxMacFilename2FSSpec( m_dir , &location ) ;
399 OSErr err = noErr ;
400
401 mDefaultLocation.descriptorType = typeNull;
402 mDefaultLocation.dataHandle = nil;
403
404 err = ::AECreateDesc(typeFSS, &location, sizeof(FSSpec), &mDefaultLocation );
405
406 if ( mDefaultLocation.dataHandle ) {
407
408 if (mSelectDefault) {
409 mNavOptions.dialogOptionFlags |= kNavSelectDefaultLocation;
410 } else {
411 mNavOptions.dialogOptionFlags &= ~kNavSelectDefaultLocation;
412 }
413 }
414
415 #if TARGET_CARBON
416 c2pstrcpy((StringPtr)mNavOptions.message, m_message) ;
417 #else
418 strcpy((char *)mNavOptions.message, m_message) ;
419 c2pstr((char *)mNavOptions.message ) ;
420 #endif
421 #if TARGET_CARBON
422 c2pstrcpy((StringPtr)mNavOptions.savedFileName, m_fileName) ;
423 #else
424 strcpy((char *)mNavOptions.savedFileName, m_fileName) ;
425 c2pstr((char *)mNavOptions.savedFileName ) ;
426 #endif
427
428 OpenUserDataRec myData;
429 MakeUserDataRec( &myData , m_wildCard ) ;
430 myData.currentfilter = m_filterIndex ;
431 if ( myData.extensions.GetCount() > 0 )
432 {
433 mNavOptions.popupExtension = (NavMenuItemSpecArrayHandle) NewHandle( sizeof( NavMenuItemSpec ) * myData.extensions.GetCount() ) ;
434 myData.menuitems = mNavOptions.popupExtension ;
435 for ( size_t i = 0 ; i < myData.extensions.GetCount() ; ++i )
436 {
437 (*mNavOptions.popupExtension)[i].version = kNavMenuItemSpecVersion ;
438 (*mNavOptions.popupExtension)[i].menuCreator = 'WXNG' ;
439 (*mNavOptions.popupExtension)[i].menuType = i ;
440 #if TARGET_CARBON
441 c2pstrcpy((StringPtr)(*mNavOptions.popupExtension)[i].menuItemName, myData.name[i]) ;
442 #else
443 strcpy((char *)(*mNavOptions.popupExtension)[i].menuItemName, myData.name[i]) ;
444 c2pstr((char *)(*mNavOptions.popupExtension)[i].menuItemName ) ;
445 #endif
446 }
447 }
448 if ( m_dialogStyle & wxSAVE )
449 {
450 myData.saveMode = true ;
451
452 mNavOptions.dialogOptionFlags |= kNavDontAutoTranslate ;
453 mNavOptions.dialogOptionFlags |= kNavDontAddTranslateItems ;
454
455 err = ::NavPutFile(
456 &mDefaultLocation,
457 &mNavReply,
458 &mNavOptions,
459 sStandardNavEventFilter ,
460 NULL,
461 kNavGenericSignature,
462 &myData); // User Data
463 m_filterIndex = myData.currentfilter ;
464 }
465 else
466 {
467 myData.saveMode = false ;
468
469 mNavFilterUPP = NewNavObjectFilterUPP( CrossPlatformFilterCallback ) ;
470 if ( m_dialogStyle & wxMULTIPLE )
471 mNavOptions.dialogOptionFlags |= kNavAllowMultipleFiles ;
472 else
473 mNavOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles ;
474
475 err = ::NavGetFile(
476 &mDefaultLocation,
477 &mNavReply,
478 &mNavOptions,
479 sStandardNavEventFilter ,
480 mNavPreviewUPP,
481 mNavFilterUPP,
482 NULL ,
483 &myData);
484 m_filterIndex = myData.currentfilter ;
485 }
486
487 DisposeNavObjectFilterUPP(mNavFilterUPP);
488 if ( mDefaultLocation.dataHandle != nil )
489 {
490 ::AEDisposeDesc(&mDefaultLocation);
491 }
492
493 if ( (err != noErr) && (err != userCanceledErr) ) {
494 m_path = "" ;
495 return wxID_CANCEL ;
496 }
497
498 if (mNavReply.validRecord) {
499
500 FSSpec outFileSpec ;
501 AEDesc specDesc ;
502 AEKeyword keyWord ;
503
504 long count ;
505 ::AECountItems( &mNavReply.selection , &count ) ;
506 for ( long i = 1 ; i <= count ; ++i )
507 {
508 OSErr err = ::AEGetNthDesc( &mNavReply.selection , i , typeFSS, &keyWord , &specDesc);
509 if ( err != noErr ) {
510 m_path = "" ;
511 return wxID_CANCEL ;
512 }
513 outFileSpec = **(FSSpec**) specDesc.dataHandle;
514 if (specDesc.dataHandle != nil) {
515 ::AEDisposeDesc(&specDesc);
516 }
517 m_path = wxMacFSSpec2MacFilename( &outFileSpec ) ;
518 m_paths.Add( m_path ) ;
519 m_fileName = wxFileNameFromPath(m_path);
520 m_fileNames.Add(m_fileName);
521 }
522 // set these to the first hit
523 m_path = m_paths[ 0 ] ;
524 m_fileName = wxFileNameFromPath(m_path);
525 m_dir = wxPathOnly(m_path);
526 NavDisposeReply( &mNavReply ) ;
527 return wxID_OK ;
528 }
529 return wxID_CANCEL;
530 }
531
532 // Generic file load/save dialog
533 static wxString
534 wxDefaultFileSelector(bool load, const char *what, const char *extension, const char *default_name, wxWindow *parent)
535 {
536 char *ext = (char *)extension;
537
538 char prompt[50];
539 wxString str;
540 if (load)
541 str = "Load %s file";
542 else
543 str = "Save %s file";
544 sprintf(prompt, wxGetTranslation(str), what);
545
546 if (*ext == '.') ext++;
547 char wild[60];
548 sprintf(wild, "*.%s", ext);
549
550 return wxFileSelector (prompt, NULL, default_name, ext, wild, 0, parent);
551 }
552
553 // Generic file load dialog
554 wxString
555 wxLoadFileSelector(const char *what, const char *extension, const char *default_name, wxWindow *parent)
556 {
557 return wxDefaultFileSelector(TRUE, what, extension, default_name, parent);
558 }
559
560
561 // Generic file save dialog
562 wxString
563 wxSaveFileSelector(const char *what, const char *extension, const char *default_name, wxWindow *parent)
564 {
565 return wxDefaultFileSelector(FALSE, what, extension, default_name, parent);
566 }
567
568