X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b600ed13625645eb985acf49eecd06fd111eb061..b9efe021b554fa3967d1442cf758435c5cd5ae8f:/src/mac/carbon/filedlg.cpp diff --git a/src/mac/carbon/filedlg.cpp b/src/mac/carbon/filedlg.cpp index d7929f00cd..60a898e95a 100644 --- a/src/mac/carbon/filedlg.cpp +++ b/src/mac/carbon/filedlg.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: filedlg.cpp -// Purpose: wxFileDialog +// Purpose: wxFileDialog // Author: Stefan Csomor // Modified by: // Created: 1998-01-01 @@ -9,25 +9,25 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "filedlg.h" #endif -#include "wx/defs.h" +#include "wx/wxprec.h" + #include "wx/app.h" #include "wx/utils.h" #include "wx/dialog.h" #include "wx/filedlg.h" #include "wx/intl.h" #include "wx/tokenzr.h" +#include "wx/filename.h" #ifndef __DARWIN__ #include "PLStringFuncs.h" #endif -#if !USE_SHARED_LIBRARY -IMPLEMENT_CLASS(wxFileDialog, wxDialog) -#endif +IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) // begin wxmac @@ -35,13 +35,8 @@ IMPLEMENT_CLASS(wxFileDialog, wxDialog) #include -#ifdef __DARWIN__ -# include "MoreFilesX.h" -#else -# include "MoreFiles.h" -# include "MoreFilesExtras.h" -#endif - +#include "MoreFilesX.h" + extern bool gUseNavServices ; // the data we need to pass to our standard file hook routine @@ -51,27 +46,24 @@ extern bool gUseNavServices ; // so we can see if the selection has changed struct OpenUserDataRec { - int currentfilter ; - bool saveMode ; + int currentfilter ; + bool saveMode ; wxArrayString name ; wxArrayString extensions ; wxArrayLong filtermactypes ; - NavMenuItemSpecArrayHandle menuitems ; + wxString defaultLocation; + CFArrayRef menuitems ; }; typedef struct OpenUserDataRec - OpenUserDataRec, *OpenUserDataRecPtr; +OpenUserDataRec, *OpenUserDataRecPtr; static pascal void NavEventProc( NavEventCallbackMessage inSelector, NavCBRecPtr ioParams, NavCallBackUserData ioUserData); -#if TARGET_CARBON - static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); -#else - static NavEventUPP sStandardNavEventFilter = NewNavEventProc(NavEventProc); -#endif +static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); static pascal void NavEventProc( @@ -80,20 +72,34 @@ NavEventProc( NavCallBackUserData ioUserData ) { OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ; - if (inSelector == kNavCBEvent) { -#if !TARGET_CARBON - wxTheApp->MacHandleOneEvent(ioParams->eventData.eventDataParms.event); -#endif - } + if (inSelector == kNavCBEvent) { + } else if ( inSelector == kNavCBStart ) { - if ( data->menuitems ) - NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &(*data->menuitems)[data->currentfilter]); + if (data && !(data->defaultLocation).IsEmpty()) + { + // Set default location for the modern Navigation APIs + // Apple Technical Q&A 1151 + FSSpec theFSSpec; + wxMacFilename2FSSpec(data->defaultLocation, &theFSSpec); + AEDesc theLocation = {typeNull, NULL}; + if (noErr == ::AECreateDesc(typeFSS, &theFSSpec, sizeof(FSSpec), &theLocation)) + ::NavCustomControl(ioParams->context, kNavCtlSetLocation, (void *) &theLocation); + } + + NavMenuItemSpec menuItem; + menuItem.version = kNavMenuItemSpecVersion; + menuItem.menuCreator = 'WXNG'; + menuItem.menuType = data->currentfilter; + wxMacStringToPascal( data->name[data->currentfilter] , (StringPtr)(menuItem.menuItemName) ) ; + ::NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &menuItem); } else if ( inSelector == kNavCBPopupMenuSelect ) { NavMenuItemSpec * menu = (NavMenuItemSpec *) ioParams->eventData.eventDataParms.param ; - if ( menu->menuCreator == 'WXNG' ) + const size_t numFilters = data->extensions.GetCount(); + + if ( menu->menuType < numFilters ) { data->currentfilter = menu->menuType ; if ( data->saveMode ) @@ -101,48 +107,30 @@ NavEventProc( int i = menu->menuType ; wxString extension = data->extensions[i].AfterLast('.') ; extension.MakeLower() ; - Str255 filename ; - // get the current filename - NavCustomControl(ioParams->context, kNavCtlGetEditFileName, &filename); - wxString sfilename = wxMacMakeStringFromPascal( filename ) ; - int pos = sfilename.Find('.',TRUE) ; + wxString sfilename ; + + wxMacCFStringHolder cfString( NavDialogGetSaveFileName( ioParams->context ) , false ); + sfilename = cfString.AsString() ; + + int pos = sfilename.Find('.', true) ; if ( pos != wxNOT_FOUND ) { sfilename = sfilename.Left(pos+1)+extension ; - wxMacStringToPascal( sfilename , filename ) ; - NavCustomControl(ioParams->context, kNavCtlSetEditFileName, &filename); + cfString.Assign( sfilename , wxFONTENCODING_DEFAULT ) ; + NavDialogSetSaveFileName( ioParams->context , cfString ) ; } } - } + } } } -const wxChar * gfilters[] = -{ - wxT("*.TXT") , - wxT("*.TIF") , - wxT("*.JPG") , - - NULL -} ; - -OSType gfiltersmac[] = -{ - 'TEXT' , - 'TIFF' , - 'JPEG' , - - '****' -} ; - - void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) { myData->menuitems = NULL ; myData->currentfilter = 0 ; - myData->saveMode = FALSE ; - + myData->saveMode = false ; + if ( filter && filter[0] ) { wxString filter2(filter) ; @@ -170,7 +158,7 @@ void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) } // we allow for compatibility reason to have a single filter expression (like *.*) without // an explanatory text, in that case the first part is name and extension at the same time - + wxASSERT_MSG( filterIndex == 0 || !isName , wxT("incorrect format of format string") ) ; if ( current.IsEmpty() ) myData->extensions.Add( myData->name[filterIndex] ) ; @@ -178,64 +166,59 @@ void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) myData->extensions.Add( current.MakeUpper() ) ; if ( filterIndex == 0 || isName ) myData->name.Add( current.MakeUpper() ) ; - + ++filterIndex ; - - + const size_t extCount = myData->extensions.GetCount(); for ( size_t i = 0 ; i < extCount; i++ ) { - int j ; - for ( j = 0 ; gfilters[j] ; j++ ) + wxUint32 fileType; + wxUint32 creator; + wxString extension = myData->extensions[i]; + + if (extension.GetChar(0) == '*') + extension = extension.Mid(1); // Remove leading * + + if (extension.GetChar(0) == '.') { - if ( myData->extensions[i] == gfilters[j] ) - { - myData->filtermactypes.Add( gfiltersmac[j] ) ; - break ; - } + extension = extension.Mid(1); // Remove leading . } - if( gfilters[j] == NULL ) + + if (wxFileName::MacFindDefaultTypeAndCreator( extension, &fileType, &creator )) { - myData->filtermactypes.Add( '****' ) ; + myData->filtermactypes.Add( (OSType)fileType ); } + else + { + myData->filtermactypes.Add( '****' ) ; // We'll fail safe if it's not recognized + } } } } -static Boolean CheckFile( ConstStr255Param name , OSType type , OpenUserDataRecPtr data) +static Boolean CheckFile( const wxString &filename , OSType type , OpenUserDataRecPtr data) { -/* - Str255 filename ; - -#if TARGET_CARBON - p2cstrcpy((char *)filename, name) ; -#else - PLstrcpy( filename , name ) ; - p2cstr( filename ) ; -#endif wxString file(filename) ; -*/ - wxString file = wxMacMakeStringFromPascal( name ) ; file.MakeUpper() ; - + if ( data->extensions.GetCount() > 0 ) { //for ( int i = 0 ; i < data->numfilters ; ++i ) int i = data->currentfilter ; if ( data->extensions[i].Right(2) == wxT(".*") ) return true ; - + { if ( type == (OSType)data->filtermactypes[i] ) return true ; - + wxStringTokenizer tokenizer( data->extensions[i] , wxT(";") ) ; while( tokenizer.HasMoreTokens() ) { wxString extension = tokenizer.GetNextToken() ; if ( extension.GetChar(0) == '*' ) extension = extension.Mid(1) ; - + if ( file.Len() >= extension.Len() && extension == file.Right(extension.Len() ) ) return true ; } @@ -245,29 +228,30 @@ static Boolean CheckFile( ConstStr255Param name , OSType type , OpenUserDataRecP return true ; } -#ifndef __DARWIN__ +#if !TARGET_API_MAC_OSX static pascal Boolean CrossPlatformFileFilter(CInfoPBPtr myCInfoPBPtr, void *dataPtr) -{ +{ OpenUserDataRecPtr data = (OpenUserDataRecPtr) dataPtr ; // return true if this item is invisible or a file Boolean visibleFlag; Boolean folderFlag; - + visibleFlag = ! (myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible); folderFlag = (myCInfoPBPtr->hFileInfo.ioFlAttrib & 0x10); - + // because the semantics of the filter proc are "true means don't show // it" we need to invert the result that we return - + if ( !visibleFlag ) return true ; - + if ( !folderFlag ) { - return !CheckFile( myCInfoPBPtr->hFileInfo.ioNamePtr , myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType , data ) ; - } - + wxString file = wxMacMakeStringFromPascal( myCInfoPBPtr->hFileInfo.ioNamePtr ) ; + return !CheckFile( file , myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType , data ) ; + } + return false ; } #endif @@ -277,193 +261,183 @@ static pascal Boolean CrossPlatformFileFilter(CInfoPBPtr myCInfoPBPtr, void *dat wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message, const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard, long style, const wxPoint& pos) + :wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos) { wxASSERT_MSG( NavServicesAvailable() , wxT("Navigation Services are not running") ) ; - m_message = message; - m_dialogStyle = style; - m_parent = parent; - m_path = wxT(""); - m_fileName = defaultFileName; - m_dir = defaultDir; - m_wildCard = wildCard; - m_filterIndex = 0; } pascal Boolean CrossPlatformFilterCallback ( - AEDesc *theItem, - void *info, - void *callBackUD, + AEDesc *theItem, + void *info, + void *callBackUD, NavFilterModes filterMode ) { bool display = true; OpenUserDataRecPtr data = (OpenUserDataRecPtr) callBackUD ; - + if (filterMode == kNavFilteringBrowserList) { NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*) info ; - if (theItem->descriptorType == typeFSS && !theInfo->isFolder) + if ( !theInfo->isFolder ) { - FSSpec spec; - memcpy( &spec , *theItem->dataHandle , sizeof(FSSpec) ) ; - display = CheckFile( spec.name , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + if (theItem->descriptorType == typeFSS ) + { + FSSpec spec; + memcpy( &spec , *theItem->dataHandle , sizeof(FSSpec) ) ; + wxString file = wxMacMakeStringFromPascal( spec.name ) ; + display = CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + } + else if ( theItem->descriptorType == typeFSRef ) + { + FSRef fsref ; + memcpy( &fsref , *theItem->dataHandle , sizeof(FSRef) ) ; + wxString file = wxMacFSRefToPath( &fsref ) ; + display = CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + } } } - + return display; } int wxFileDialog::ShowModal() { - NavDialogOptions mNavOptions; - NavObjectFilterUPP mNavFilterUPP = NULL; - NavPreviewUPP mNavPreviewUPP = NULL ; - NavReplyRecord mNavReply; - AEDesc mDefaultLocation ; - bool mSelectDefault = false ; - - // setup dialog - - ::NavGetDefaultDialogOptions(&mNavOptions); - - mNavFilterUPP = nil; - mNavPreviewUPP = nil; - mSelectDefault = false; - mNavReply.validRecord = false; - mNavReply.replacing = false; - mNavReply.isStationery = false; - mNavReply.translationNeeded = false; - mNavReply.selection.descriptorType = typeNull; - mNavReply.selection.dataHandle = nil; - mNavReply.keyScript = smSystemScript; - mNavReply.fileTranslation = nil; - - // Set default location, the location - // that's displayed when the dialog - // first appears - - FSSpec location ; - wxMacFilename2FSSpec( m_dir , &location ) ; - OSErr err = noErr ; - - mDefaultLocation.descriptorType = typeNull; - mDefaultLocation.dataHandle = nil; - - err = ::AECreateDesc(typeFSS, &location, sizeof(FSSpec), &mDefaultLocation ); - - if ( mDefaultLocation.dataHandle ) { - - if (mSelectDefault) { - mNavOptions.dialogOptionFlags |= kNavSelectDefaultLocation; - } else { - mNavOptions.dialogOptionFlags &= ~kNavSelectDefaultLocation; + OSErr err; + NavDialogCreationOptions dialogCreateOptions; + // set default options + ::NavGetDefaultDialogCreationOptions(&dialogCreateOptions); + + // this was always unset in the old code + dialogCreateOptions.optionFlags &= ~kNavSelectDefaultLocation; + + wxMacCFStringHolder message(m_message, m_font.GetEncoding()); + dialogCreateOptions.windowTitle = message; + + wxMacCFStringHolder defaultFileName(m_fileName, m_font.GetEncoding()); + dialogCreateOptions.saveFileName = defaultFileName; + + + NavDialogRef dialog; + NavObjectFilterUPP navFilterUPP = NULL; + CFArrayRef cfArray = NULL; // for popupExtension + OpenUserDataRec myData; + myData.defaultLocation = m_dir; + + MakeUserDataRec(&myData , m_wildCard); + myData.currentfilter = m_filterIndex; + size_t numFilters = myData.extensions.GetCount(); + if (numFilters) + { + CFMutableArrayRef popup = CFArrayCreateMutable( kCFAllocatorDefault , + numFilters , &kCFTypeArrayCallBacks ) ; + dialogCreateOptions.popupExtension = popup ; + myData.menuitems = dialogCreateOptions.popupExtension ; + for ( size_t i = 0 ; i < numFilters ; ++i ) + { + CFArrayAppendValue( popup , (CFStringRef) wxMacCFStringHolder( myData.name[i] , m_font.GetEncoding() ) ) ; } } - wxMacStringToPascal( m_message , (StringPtr)mNavOptions.message ) ; - wxMacStringToPascal( m_fileName , (StringPtr)mNavOptions.savedFileName ) ; - // zero all data - - m_path = wxEmptyString ; - m_fileName = wxEmptyString ; - m_paths.Empty(); - m_fileNames.Empty(); - - OpenUserDataRec myData; - MakeUserDataRec( &myData , m_wildCard ) ; - myData.currentfilter = m_filterIndex ; - if ( myData.extensions.GetCount() > 0 ) + if (m_dialogStyle & wxSAVE) { - mNavOptions.popupExtension = (NavMenuItemSpecArrayHandle) NewHandle( sizeof( NavMenuItemSpec ) * myData.extensions.GetCount() ) ; - myData.menuitems = mNavOptions.popupExtension ; - for ( size_t i = 0 ; i < myData.extensions.GetCount() ; ++i ) + myData.saveMode = true; + + if (!numFilters) { - (*mNavOptions.popupExtension)[i].version = kNavMenuItemSpecVersion ; - (*mNavOptions.popupExtension)[i].menuCreator = 'WXNG' ; - (*mNavOptions.popupExtension)[i].menuType = i ; - wxMacStringToPascal( myData.name[i] , (StringPtr)(*mNavOptions.popupExtension)[i].menuItemName ) ; + dialogCreateOptions.optionFlags |= kNavNoTypePopup; } + dialogCreateOptions.optionFlags |= kNavDontAutoTranslate; + dialogCreateOptions.optionFlags |= kNavDontAddTranslateItems; + + // The extension is important + if (numFilters < 2) + dialogCreateOptions.optionFlags |= kNavPreserveSaveFileExtension; + +#if TARGET_API_MAC_OSX + if (!(m_dialogStyle & wxOVERWRITE_PROMPT)) + { + dialogCreateOptions.optionFlags |= kNavDontConfirmReplacement; + } +#endif + err = ::NavCreatePutFileDialog(&dialogCreateOptions, + // Suppresses the 'Default' (top) menu item + kNavGenericSignature, kNavGenericSignature, + sStandardNavEventFilter, + &myData, // for defaultLocation + &dialog); } - if ( m_dialogStyle & wxSAVE ) + else { - myData.saveMode = true ; - - mNavOptions.dialogOptionFlags |= kNavDontAutoTranslate ; - mNavOptions.dialogOptionFlags |= kNavDontAddTranslateItems ; - - err = ::NavPutFile( - &mDefaultLocation, - &mNavReply, - &mNavOptions, - sStandardNavEventFilter , - NULL, - kNavGenericSignature, - &myData); // User Data - m_filterIndex = myData.currentfilter ; + + //let people select bundles/programs in dialogs + dialogCreateOptions.optionFlags |= kNavSupportPackages; + + navFilterUPP = NewNavObjectFilterUPP(CrossPlatformFilterCallback); + err = ::NavCreateGetFileDialog(&dialogCreateOptions, + NULL, // NavTypeListHandle + sStandardNavEventFilter, + NULL, // NavPreviewUPP + navFilterUPP, + (void *) &myData, // inClientData + &dialog); } - else + + if (err == noErr) + err = ::NavDialogRun(dialog); + + // clean up filter related data, etc. + if (navFilterUPP) + ::DisposeNavObjectFilterUPP(navFilterUPP); + if (cfArray) + ::CFRelease(cfArray); + + if (err != noErr) + return wxID_CANCEL; + + NavReplyRecord navReply; + err = ::NavDialogGetReply(dialog, &navReply); + if (err == noErr && navReply.validRecord) { - myData.saveMode = false ; + AEKeyword theKeyword; + DescType actualType; + Size actualSize; + FSRef theFSRef; + wxString thePath ; - mNavFilterUPP = NewNavObjectFilterUPP( CrossPlatformFilterCallback ) ; - if ( m_dialogStyle & wxMULTIPLE ) - mNavOptions.dialogOptionFlags |= kNavAllowMultipleFiles ; - else - mNavOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles ; - - err = ::NavGetFile( - &mDefaultLocation, - &mNavReply, - &mNavOptions, - sStandardNavEventFilter , - mNavPreviewUPP, - mNavFilterUPP, - NULL , - &myData); m_filterIndex = myData.currentfilter ; - } - - DisposeNavObjectFilterUPP(mNavFilterUPP); - if ( mDefaultLocation.dataHandle != nil ) - { - ::AEDisposeDesc(&mDefaultLocation); - } - - if ( (err != noErr) && (err != userCanceledErr) ) { - return wxID_CANCEL ; - } - if (mNavReply.validRecord) { - - FSSpec outFileSpec ; - AEDesc specDesc ; - AEKeyword keyWord ; - - long count ; - ::AECountItems( &mNavReply.selection , &count ) ; - for ( long i = 1 ; i <= count ; ++i ) + long count; + ::AECountItems(&navReply.selection , &count); + for (long i = 1; i <= count; ++i) { - OSErr err = ::AEGetNthDesc( &mNavReply.selection , i , typeFSS, &keyWord , &specDesc); - if ( err != noErr ) { - m_path = wxT("") ; - return wxID_CANCEL ; - } - outFileSpec = **(FSSpec**) specDesc.dataHandle; - if (specDesc.dataHandle != nil) { - ::AEDisposeDesc(&specDesc); + err = ::AEGetNthPtr(&(navReply.selection), i, typeFSRef, &theKeyword, &actualType, + &theFSRef, sizeof(theFSRef), &actualSize); + if (err != noErr) + break; + + if (m_dialogStyle & wxSAVE) + thePath = wxMacFSRefToPath( &theFSRef , navReply.saveFileName ) ; + else + thePath = wxMacFSRefToPath( &theFSRef ) ; + + if (!thePath) + { + ::NavDisposeReply(&navReply); + return wxID_CANCEL; } - m_path = wxMacFSSpec2MacFilename( &outFileSpec ) ; - m_paths.Add( m_path ) ; + m_path = thePath; + m_paths.Add(m_path); m_fileName = wxFileNameFromPath(m_path); m_fileNames.Add(m_fileName); } // set these to the first hit - m_path = m_paths[ 0 ] ; + m_path = m_paths[0]; m_fileName = wxFileNameFromPath(m_path); m_dir = wxPathOnly(m_path); - NavDisposeReply( &mNavReply ) ; - return wxID_OK ; } - return wxID_CANCEL; + ::NavDisposeReply(&navReply); + + return (err == noErr) ? wxID_OK : wxID_CANCEL; }