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