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