]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/filedlg.cpp
Committed Stefan's temporary fix for crashing in Mac Classic.
[wxWidgets.git] / src / mac / carbon / filedlg.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: filedlg.cpp
2f1ae414 3// Purpose: wxFileDialog
e9576ca5
SC
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"
5fde6fcc 17#include "wx/app.h"
e9576ca5
SC
18#include "wx/utils.h"
19#include "wx/dialog.h"
20#include "wx/filedlg.h"
21#include "wx/intl.h"
fe35d097 22#include "wx/tokenzr.h"
e9576ca5 23
f11bdd03 24#ifndef __DARWIN__
03e11df5
GD
25 #include "PLStringFuncs.h"
26#endif
5b781a67 27
2f1ae414 28#if !USE_SHARED_LIBRARY
e9576ca5 29IMPLEMENT_CLASS(wxFileDialog, wxDialog)
2f1ae414 30#endif
e9576ca5 31
519cb848
SC
32// begin wxmac
33
76a5e5d2
SC
34#include "wx/mac/private.h"
35
bb378910 36#include <Navigation.h>
5b781a67 37
da2b4b7a
GD
38#include "MoreFiles.h"
39#include "MoreFilesExtras.h"
519cb848 40
5b781a67
SC
41extern bool gUseNavServices ;
42
4d4d8bbf
SC
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
4d4d8bbf
SC
49struct OpenUserDataRec {
50 int currentfilter ;
2b5f62a0
VZ
51 bool saveMode ;
52 wxArrayString name ;
53 wxArrayString extensions ;
54 wxArrayLong filtermactypes ;
55 NavMenuItemSpecArrayHandle menuitems ;
4d4d8bbf 56};
2b5f62a0 57
4d4d8bbf
SC
58typedef struct OpenUserDataRec
59 OpenUserDataRec, *OpenUserDataRecPtr;
60
5b781a67
SC
61static 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
72static pascal void
73NavEventProc(
74 NavEventCallbackMessage inSelector,
75 NavCBRecPtr ioParams,
4d4d8bbf 76 NavCallBackUserData ioUserData )
5b781a67 77{
2b5f62a0 78 OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ;
5b781a67 79 if (inSelector == kNavCBEvent) {
5fde6fcc 80 wxTheApp->MacHandleOneEvent(ioParams->eventData.eventDataParms.event);
2b5f62a0
VZ
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 )
4d4d8bbf 88 {
2b5f62a0
VZ
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 }
5b781a67
SC
112 }
113}
114
72055702 115const char * gfilters[] =
519cb848
SC
116{
117 "*.TXT" ,
4d4d8bbf
SC
118 "*.TIF" ,
119 "*.JPG" ,
519cb848
SC
120
121 NULL
122} ;
123
124OSType gfiltersmac[] =
125{
126 'TEXT' ,
4d4d8bbf
SC
127 'TIFF' ,
128 'JPEG' ,
519cb848
SC
129
130 '****'
131} ;
132
2f1ae414 133
519cb848 134
4d4d8bbf
SC
135void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter )
136{
2b5f62a0
VZ
137 myData->menuitems = NULL ;
138 myData->currentfilter = 0 ;
139 myData->saveMode = FALSE ;
140
4d4d8bbf
SC
141 if ( filter && filter[0] )
142 {
143 wxString filter2(filter) ;
144 int filterIndex = 0;
145 bool isName = true ;
146 wxString current ;
2b5f62a0 147 for( unsigned int i = 0; i < filter2.Len() ; i++ )
4d4d8bbf
SC
148 {
149 if( filter2.GetChar(i) == wxT('|') )
150 {
151 if( isName ) {
2b5f62a0 152 myData->name.Add( current ) ;
4d4d8bbf
SC
153 }
154 else {
2b5f62a0 155 myData->extensions.Add( current.MakeUpper() ) ;
4d4d8bbf
SC
156 ++filterIndex ;
157 }
158 isName = !isName ;
159 current = "" ;
160 }
161 else
162 {
163 current += filter2.GetChar(i) ;
164 }
165 }
d1aba6db
SC
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() )
2b5f62a0 171 myData->extensions.Add( myData->name[filterIndex] ) ;
d1aba6db 172 else
2b5f62a0
VZ
173 myData->extensions.Add( current.MakeUpper() ) ;
174 if ( filterIndex == 0 || isName )
175 myData->name.Add( current.MakeUpper() ) ;
176
d1aba6db
SC
177 ++filterIndex ;
178
4d4d8bbf 179
2b5f62a0
VZ
180 const size_t extCount = myData->extensions.GetCount();
181 for ( size_t i = 0 ; i < extCount; i++ )
4d4d8bbf
SC
182 {
183 int j ;
184 for ( j = 0 ; gfilters[j] ; j++ )
185 {
186 if ( strcmp( myData->extensions[i] , gfilters[j] ) == 0 )
187 {
2b5f62a0 188 myData->filtermactypes.Add( gfiltersmac[j] ) ;
4d4d8bbf
SC
189 break ;
190 }
191 }
192 if( gfilters[j] == NULL )
193 {
2b5f62a0 194 myData->filtermactypes.Add( '****' ) ;
4d4d8bbf
SC
195 }
196 }
197 }
4d4d8bbf 198}
bb378910 199
4d4d8bbf
SC
200static Boolean CheckFile( ConstStr255Param name , OSType type , OpenUserDataRecPtr data)
201{
da2b4b7a
GD
202 Str255 filename ;
203
204#if TARGET_CARBON
205 p2cstrcpy((char *)filename, name) ;
206#else
207 PLstrcpy( filename , name ) ;
9f92f6fb 208 p2cstr( filename ) ;
da2b4b7a 209#endif
9f92f6fb
SC
210 wxString file(filename) ;
211 file.MakeUpper() ;
212
2b5f62a0 213 if ( data->extensions.GetCount() > 0 )
da2b4b7a
GD
214 {
215 //for ( int i = 0 ; i < data->numfilters ; ++i )
fe35d097
SC
216 int i = data->currentfilter ;
217 if ( data->extensions[i].Right(2) == ".*" )
218 return true ;
da2b4b7a 219
fe35d097 220 {
2b5f62a0 221 if ( type == (OSType)data->filtermactypes[i] )
fe35d097 222 return true ;
da2b4b7a 223
fe35d097
SC
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 ;
da2b4b7a
GD
236 }
237 return true ;
4d4d8bbf
SC
238}
239
bb378910 240#ifndef __DARWIN__
5fde6fcc 241static pascal Boolean CrossPlatformFileFilter(CInfoPBPtr myCInfoPBPtr, void *dataPtr)
519cb848 242{
519cb848
SC
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 {
4d4d8bbf 260 return !CheckFile( myCInfoPBPtr->hFileInfo.ioNamePtr , myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType , data ) ;
519cb848
SC
261 }
262
263 return false ;
264}
bb378910 265#endif
519cb848
SC
266
267// end wxmac
268
269wxString wxFileSelector(const char *title,
e9576ca5
SC
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
8be97d65 303 return wxGetEmptyString();
e9576ca5
SC
304}
305
169935ad 306WXDLLEXPORT wxString wxFileSelectorEx(const char *title,
e9576ca5
SC
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
8be97d65 327 return wxGetEmptyString();
e9576ca5
SC
328}
329
330wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message,
331 const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard,
332 long style, const wxPoint& pos)
333{
2b5f62a0 334 wxASSERT_MSG( NavServicesAvailable() , "Navigation Services are not running" ) ;
e9576ca5
SC
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;
2b5f62a0 342 m_filterIndex = 0;
e9576ca5
SC
343}
344
4d4d8bbf 345
f11bdd03 346pascal Boolean CrossPlatformFilterCallback (
4d4d8bbf
SC
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;
fe35d097 362 memcpy( &spec , *theItem->dataHandle , sizeof(FSSpec) ) ;
4d4d8bbf
SC
363 display = CheckFile( spec.name , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ;
364 }
365 }
366
367 return display;
368}
369
e9576ca5
SC
370int wxFileDialog::ShowModal()
371{
5b781a67
SC
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 ;
bedaf53e 398 wxMacFilename2FSSpec( m_dir , &location ) ;
5b781a67
SC
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
03e11df5
GD
415#if TARGET_CARBON
416 c2pstrcpy((StringPtr)mNavOptions.message, m_message) ;
417#else
5b781a67
SC
418 strcpy((char *)mNavOptions.message, m_message) ;
419 c2pstr((char *)mNavOptions.message ) ;
03e11df5
GD
420#endif
421#if TARGET_CARBON
422 c2pstrcpy((StringPtr)mNavOptions.savedFileName, m_fileName) ;
423#else
5b781a67
SC
424 strcpy((char *)mNavOptions.savedFileName, m_fileName) ;
425 c2pstr((char *)mNavOptions.savedFileName ) ;
03e11df5 426#endif
5b781a67 427
2b5f62a0
VZ
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 ;
7baf4bdb 435 for ( size_t i = 0 ; i < myData.extensions.GetCount() ; ++i )
2b5f62a0
VZ
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 }
5b781a67
SC
448 if ( m_dialogStyle & wxSAVE )
449 {
2b5f62a0
VZ
450 myData.saveMode = true ;
451
5b781a67
SC
452 mNavOptions.dialogOptionFlags |= kNavDontAutoTranslate ;
453 mNavOptions.dialogOptionFlags |= kNavDontAddTranslateItems ;
454
455 err = ::NavPutFile(
456 &mDefaultLocation,
457 &mNavReply,
458 &mNavOptions,
459 sStandardNavEventFilter ,
2b5f62a0
VZ
460 NULL,
461 kNavGenericSignature,
462 &myData); // User Data
463 m_filterIndex = myData.currentfilter ;
5b781a67
SC
464 }
465 else
466 {
2b5f62a0 467 myData.saveMode = false ;
4d4d8bbf 468
2b5f62a0 469 mNavFilterUPP = NewNavObjectFilterUPP( CrossPlatformFilterCallback ) ;
5b781a67
SC
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,
2b5f62a0
VZ
482 NULL ,
483 &myData);
484 m_filterIndex = myData.currentfilter ;
5b781a67
SC
485 }
486
4d4d8bbf 487 DisposeNavObjectFilterUPP(mNavFilterUPP);
5b781a67
SC
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 ;
fe35d097 502 AEKeyword keyWord ;
5b781a67
SC
503
504 long count ;
505 ::AECountItems( &mNavReply.selection , &count ) ;
506 for ( long i = 1 ; i <= count ; ++i )
507 {
fe35d097 508 OSErr err = ::AEGetNthDesc( &mNavReply.selection , i , typeFSS, &keyWord , &specDesc);
5b781a67
SC
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 }
bedaf53e 517 m_path = wxMacFSSpec2MacFilename( &outFileSpec ) ;
5b781a67 518 m_paths.Add( m_path ) ;
24fe8dc7
SC
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 ;
5b781a67
SC
528 }
529 return wxID_CANCEL;
5b781a67 530}
e9576ca5
SC
531
532// Generic file load/save dialog
169935ad 533static wxString
e9576ca5
SC
534wxDefaultFileSelector(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
169935ad 554wxString
e9576ca5
SC
555wxLoadFileSelector(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
169935ad 562wxString
e9576ca5
SC
563wxSaveFileSelector(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