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