CW5.2 Pro Adaptions, wxMac starting to move in
[wxWidgets.git] / src / mac / 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/utils.h"
18 #include "wx/dialog.h"
19 #include "wx/filedlg.h"
20 #include "wx/intl.h"
21
22 #if !USE_SHARED_LIBRARY
23 IMPLEMENT_CLASS(wxFileDialog, wxDialog)
24 #endif
25
26 // begin wxmac
27
28 #include "morefile.h"
29 #include "moreextr.h"
30 #include "fullpath.h"
31 #include "fspcompa.h"
32 #include "PLStringFuncs.h"
33
34 char * gfilters[] =
35 {
36 "*.TXT" ,
37
38 NULL
39 } ;
40
41 OSType gfiltersmac[] =
42 {
43 'TEXT' ,
44
45 '****'
46 } ;
47
48 static void wxMacSetupStandardFile(short newVRefNum, long newDirID)
49 {
50 enum
51 { SFSaveDisk = 0x214, CurDirStore = 0x398 };
52 *(short *) SFSaveDisk = -1 * newVRefNum;
53 *(long *) CurDirStore = newDirID;
54 }
55
56 static void wxMacSetupStandardFileFromPath( const char* s )
57 {
58 Str255 volume ;
59 Str255 path ;
60 short vRefNum ;
61 long dirRef ;
62 short i,j ;
63 Boolean isDirectory ;
64
65 for (i=0 ; (s[i]!=0) && (s[i]!=':') ;i++)
66 {
67 volume[i]=s[i] ;
68 }
69 volume[i]=':' ;
70 volume[i+1]=0 ;
71
72 // then copy the rest of the filename
73
74 for (j=0;(s[i]!=0);i++,j++)
75 {
76 path[j]=s[i] ;
77 }
78 path[j]=0 ;
79
80 c2pstr((Ptr) volume) ;
81 c2pstr((Ptr) path) ;
82
83 SetVol(volume, 0) ;
84 GetVol( NULL, &vRefNum ) ;
85
86 GetDirectoryID( vRefNum , fsRtDirID , path , &dirRef , &isDirectory ) ;
87 wxMacSetupStandardFile(vRefNum, dirRef) ;
88 }
89
90 enum {
91 kSelectItem = 10, // select button item number
92 kSFGetFileDlgID = 251, // dialog resource number
93 kStrListID = 251, // our strings
94 kSelectStrNum = 1, // word 'Select: ' for button
95 kDesktopStrNum = 2, // word 'Desktop' for button
96 kSelectNoQuoteStrNum = 3, // word 'Select: ' for button
97
98 kUseQuotes = true, // parameter for SetButtonName
99 kDontUseQuotes = false
100 };
101
102 // the data we need to pass to our standard file hook routine
103 // includes a pointer to the dialog, a pointer to the standard
104 // file reply record (so we can inspect the current selection)
105 // and a copy of the "previous" file spec of the reply record
106 // so we can see if the selection has changed
107
108 const int kwxMacFileTypes = 10 ;
109
110 struct OpenUserDataRec {
111 StandardFileReply *sfrPtr;
112 FSSpec oldSelectionFSSpec;
113 char filter[kwxMacFileTypes][10] ;
114 OSType filtermactypes[kwxMacFileTypes] ;
115 int numfilters ;
116 DialogPtr theDlgPtr;
117 };
118 typedef struct OpenUserDataRec
119 OpenUserDataRec, *OpenUserDataRecPtr;
120
121 static void GetLabelString(StringPtr theStr, short stringNum)
122 {
123 GetIndString(theStr, kStrListID, stringNum);
124 }
125
126 static void CopyPStr(StringPtr src, StringPtr dest)
127 {
128 BlockMoveData(src, dest, 1 + src[0]);
129 }
130
131 static char GetSelectKey(void)
132 {
133 // this is the key used to trigger the select button
134
135 // NOT INTERNATIONAL SAVVY; should at least grab it from resources
136
137 return 's';
138 }
139
140 // FlashButton briefly highlights the dialog button
141 // as feedback for key equivalents
142
143 static void FlashButton(DialogPtr theDlgPtr, short buttonID)
144 {
145 short buttonType;
146 Handle buttonHandle;
147 Rect buttonRect;
148 unsigned long finalTicks;
149
150 GetDialogItem(theDlgPtr, buttonID, &buttonType, &buttonHandle, &buttonRect);
151 HiliteControl((ControlHandle) buttonHandle, kControlButtonPart);
152 Delay(10, &finalTicks);
153 HiliteControl((ControlHandle) buttonHandle, 0);
154 }
155
156 static Boolean SameFSSpec(FSSpecPtr spec1, FSSpecPtr spec2)
157 {
158 return (spec1->vRefNum == spec2->vRefNum
159 && spec1->parID == spec2->parID
160 && EqualString(spec1->name, spec2->name, false, false));
161 }
162 // MyModalDialogFilter maps a key to the Select button, and handles
163 // flashing of the button when the key is hit
164
165 static pascal Boolean SFGetFolderModalDialogFilter(DialogPtr theDlgPtr, EventRecord *eventRec,
166 short *item, Ptr dataPtr)
167 {
168 #pragma unused (dataPtr)
169
170 // make certain the proper dialog is showing, 'cause standard file
171 // can nest dialogs but calls the same filter for each
172
173 if (((WindowPeek) theDlgPtr)->refCon == sfMainDialogRefCon)
174 {
175 // check if the select button was hit
176 /*
177 if ((eventRec->what == keyDown)
178 && (eventRec->modifiers & cmdKey)
179 && ((eventRec->message & charCodeMask) == GetSelectKey()))
180 {
181 *item = kSelectItem;
182 FlashButton(theDlgPtr, kSelectItem);
183 return true;
184 }
185 */
186 }
187
188 return false;
189 }
190
191 void ExtendedOpenFile( ConstStr255Param message , ConstStr255Param path , const char *filter , FileFilterYDUPP fileFilter, StandardFileReply *theSFR)
192 {
193 Point thePt;
194 OpenUserDataRec myData;
195 FSSpec tempSpec;
196 Boolean folderFlag;
197 Boolean wasAliasedFlag;
198 DlgHookYDUPP dlgHookUPP;
199 ModalFilterYDUPP myModalFilterUPP;
200 OSErr err;
201 SFTypeList types ;
202
203
204 // presumably we're running System 7 or later so CustomGetFile is
205 // available
206
207 // set initial contents of Select button to a space
208
209 CopyPStr("\p ", theSFR->sfFile.name);
210
211 // point the user data parameter at the reply record so we can get to it later
212
213 myData.sfrPtr = theSFR;
214 if ( filter && filter[0] )
215 {
216 myData.numfilters = 1 ;
217 for ( int i = 0 ; i < myData.numfilters ; i++ )
218 {
219 int j ;
220
221 strcpy( myData.filter[i] , filter ) ;
222 for( j = 0 ; myData.filter[i][j] ; j++ )
223 {
224 myData.filter[i][j] = toupper( myData.filter[i][j] ) ;
225 }
226 for ( j = 0 ; gfilters[j] ; j++ )
227 {
228 if ( strcmp( myData.filter[i] , gfilters[j] ) == 0 )
229 {
230 myData.filtermactypes[i] = gfiltersmac[j] ;
231 break ;
232 }
233 }
234 if( gfilters[j] == NULL )
235 {
236 myData.filtermactypes[i] = '****' ;
237 }
238 }
239 }
240 else
241 {
242 myData.numfilters = 0 ;
243 }
244 // display the dialog
245
246 dlgHookUPP = NULL ;
247 // dlgHookUPP = NewDlgHookYDProc(SFGetFolderDialogHook);
248 myModalFilterUPP = NewModalFilterYDProc(SFGetFolderModalDialogFilter);
249
250 thePt.h = thePt.v = -1; // center dialog
251
252 ParamText( message , NULL , NULL , NULL ) ;
253
254 CustomGetFile( fileFilter,
255 -1, // show all types
256 NULL,
257 theSFR,
258 kSFGetFileDlgID,
259 thePt, // top left point
260 dlgHookUPP,
261 myModalFilterUPP,
262 nil, // activate list
263 nil, // activate proc
264 &myData);
265
266 DisposeRoutineDescriptor(dlgHookUPP);
267 DisposeRoutineDescriptor(myModalFilterUPP);
268
269 // if cancel wasn't pressed and no fatal error occurred...
270
271 if (theSFR->sfGood)
272 {
273 // if no name is in the reply record file spec,
274 // use the file spec of the parent folder
275
276 if (theSFR->sfFile.name[0] == '\0')
277 {
278 err = FSMakeFSSpec(theSFR->sfFile.vRefNum, theSFR->sfFile.parID,
279 "\p", &tempSpec);
280 if (err == noErr)
281 {
282 theSFR->sfFile = tempSpec;
283 }
284 else
285 {
286 // no name to return, forget it
287
288 theSFR->sfGood = false;
289 }
290 }
291
292 // if there is now a name in the file spec, check if it's
293 // for a folder or a volume
294
295 if (theSFR->sfFile.name[0] != '\0')
296 {
297 // the parID of the root of a disk is always fsRtParID == 1
298
299 if (theSFR->sfFile.parID == fsRtParID)
300 {
301 theSFR->sfIsVolume = true;
302 theSFR->sfIsFolder = false; // it would be reasonable for this to be true, too
303 }
304
305 // we have a valid FSSpec, now let's make sure it's not for an alias file
306
307 err = ResolveAliasFile(&theSFR->sfFile, true, &folderFlag, &wasAliasedFlag);
308 if (err != noErr)
309 {
310 theSFR->sfGood = false;
311 }
312
313 // did the alias resolve to a folder?
314
315 if (folderFlag && ! theSFR->sfIsVolume)
316 {
317 theSFR->sfIsFolder = true;
318 }
319 }
320 }
321 }
322
323 static pascal Boolean CrossPlatformFileFilter(CInfoPBPtr myCInfoPBPtr, Ptr dataPtr)
324 {
325 Str255 filename ;
326 OpenUserDataRecPtr data = (OpenUserDataRecPtr) dataPtr ;
327 // return true if this item is invisible or a file
328
329 Boolean visibleFlag;
330 Boolean folderFlag;
331
332 visibleFlag = ! (myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible);
333 folderFlag = (myCInfoPBPtr->hFileInfo.ioFlAttrib & 0x10);
334
335 // because the semantics of the filter proc are "true means don't show
336 // it" we need to invert the result that we return
337
338 if ( !visibleFlag )
339 return true ;
340
341 if ( !folderFlag )
342 {
343 if ( data->numfilters > 0 )
344 {
345 PLstrcpy( filename ,myCInfoPBPtr->hFileInfo.ioNamePtr ) ;
346 if ( filename[0] >= 4 )
347 {
348 for( int j = 1 ; j <= filename[0] ; j++ )
349 {
350 filename[j] = toupper( filename[j] ) ;
351 }
352 for ( int i = 0 ; i < data->numfilters ; ++i )
353 {
354 if ( myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType == data->filtermactypes[i] )
355 return false ;
356
357 if ( strncmp( (char*) filename + 1 + filename[0] - 4 ,
358 & data->filter[i][ strlen(data->filter[i]) - 4 ] , 4 ) == 0 )
359 return false ;
360 }
361 }
362 return true ;
363 }
364 }
365
366 return false ;
367 }
368
369 // end wxmac
370
371 wxString wxFileSelector(const char *title,
372 const char *defaultDir, const char *defaultFileName,
373 const char *defaultExtension, const char *filter, int flags,
374 wxWindow *parent, int x, int y)
375 {
376 // If there's a default extension specified but no filter, we create a suitable
377 // filter.
378
379 wxString filter2("");
380 if ( defaultExtension && !filter )
381 filter2 = wxString("*.") + wxString(defaultExtension) ;
382 else if ( filter )
383 filter2 = filter;
384
385 wxString defaultDirString;
386 if (defaultDir)
387 defaultDirString = defaultDir;
388 else
389 defaultDirString = "";
390
391 wxString defaultFilenameString;
392 if (defaultFileName)
393 defaultFilenameString = defaultFileName;
394 else
395 defaultFilenameString = "";
396
397 wxFileDialog fileDialog(parent, title, defaultDirString, defaultFilenameString, filter2, flags, wxPoint(x, y));
398
399 if ( fileDialog.ShowModal() == wxID_OK )
400 {
401 strcpy(wxBuffer, (const char *)fileDialog.GetPath());
402 return wxBuffer;
403 }
404 else
405 return wxGetEmptyString();
406 }
407
408 WXDLLEXPORT wxString wxFileSelectorEx(const char *title,
409 const char *defaultDir,
410 const char *defaultFileName,
411 int* defaultFilterIndex,
412 const char *filter,
413 int flags,
414 wxWindow* parent,
415 int x,
416 int y)
417
418 {
419 wxFileDialog fileDialog(parent, title ? title : "", defaultDir ? defaultDir : "",
420 defaultFileName ? defaultFileName : "", filter ? filter : "", flags, wxPoint(x, y));
421
422 if ( fileDialog.ShowModal() == wxID_OK )
423 {
424 *defaultFilterIndex = fileDialog.GetFilterIndex();
425 strcpy(wxBuffer, (const char *)fileDialog.GetPath());
426 return wxBuffer;
427 }
428 else
429 return wxGetEmptyString();
430 }
431
432 wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message,
433 const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard,
434 long style, const wxPoint& pos)
435 {
436 m_message = message;
437 m_dialogStyle = style;
438 m_parent = parent;
439 m_path = "";
440 m_fileName = defaultFileName;
441 m_dir = defaultDir;
442 m_wildCard = wildCard;
443 m_filterIndex = 1;
444 }
445
446 int wxFileDialog::ShowModal()
447 {
448 if ( m_dialogStyle & wxSAVE )
449 {
450 StandardFileReply reply ;
451 Str255 prompt ;
452 Str255 filename ;
453
454 strcpy((char *)prompt, m_message) ;
455 c2pstr((char *)prompt ) ;
456
457 strcpy((char *)filename, m_fileName) ;
458 c2pstr((char *)filename ) ;
459
460 StandardPutFile( prompt , filename , &reply ) ;
461 if ( reply.sfGood == false )
462 {
463 m_path = "" ;
464 return wxID_CANCEL ;
465 }
466 else
467 {
468 m_path = wxMacFSSpec2UnixFilename( &reply.sfFile ) ;
469 return wxID_OK ;
470 }
471 }
472 else
473 {
474 OSType types = '????' ;
475 Str255 prompt ;
476 Str255 path ;
477
478 strcpy((char *)prompt, m_message) ;
479 c2pstr((char *)prompt ) ;
480
481 strcpy((char *)path, m_path ) ;
482 c2pstr((char *)path ) ;
483
484 FileFilterYDUPP crossPlatformFileFilterUPP;
485 StandardFileReply reply ;
486 crossPlatformFileFilterUPP =
487 NewFileFilterYDProc(CrossPlatformFileFilter);
488
489 ExtendedOpenFile( prompt , path , m_wildCard , crossPlatformFileFilterUPP, &reply);
490
491 DisposeRoutineDescriptor(crossPlatformFileFilterUPP);
492 if ( reply.sfGood == false )
493 {
494 m_path = "" ;
495 return wxID_CANCEL ;
496 }
497 else
498 {
499 m_path = wxMacFSSpec2UnixFilename( &reply.sfFile ) ;
500 return wxID_OK ;
501 }
502 }
503 return wxID_CANCEL;
504 }
505
506 // Generic file load/save dialog
507 static wxString
508 wxDefaultFileSelector(bool load, const char *what, const char *extension, const char *default_name, wxWindow *parent)
509 {
510 char *ext = (char *)extension;
511
512 char prompt[50];
513 wxString str;
514 if (load)
515 str = "Load %s file";
516 else
517 str = "Save %s file";
518 sprintf(prompt, wxGetTranslation(str), what);
519
520 if (*ext == '.') ext++;
521 char wild[60];
522 sprintf(wild, "*.%s", ext);
523
524 return wxFileSelector (prompt, NULL, default_name, ext, wild, 0, parent);
525 }
526
527 // Generic file load dialog
528 wxString
529 wxLoadFileSelector(const char *what, const char *extension, const char *default_name, wxWindow *parent)
530 {
531 return wxDefaultFileSelector(TRUE, what, extension, default_name, parent);
532 }
533
534
535 // Generic file save dialog
536 wxString
537 wxSaveFileSelector(const char *what, const char *extension, const char *default_name, wxWindow *parent)
538 {
539 return wxDefaultFileSelector(FALSE, what, extension, default_name, parent);
540 }
541
542