X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3d1a4878f36ba4b5f66c2ccfd2cb27a9dc528b6f..9d5507f7a2701395e1d5c121bd877bb9066ee6ea:/src/mac/carbon/filedlg.cpp?ds=sidebyside diff --git a/src/mac/carbon/filedlg.cpp b/src/mac/carbon/filedlg.cpp index fc125d5921..81845d173e 100644 --- a/src/mac/carbon/filedlg.cpp +++ b/src/mac/carbon/filedlg.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: filedlg.cpp +// Name: src/mac/carbon/filedlg.cpp // Purpose: wxFileDialog // Author: Stefan Csomor // Modified by: @@ -9,37 +9,30 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "filedlg.h" -#endif - #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" +#if wxUSE_FILEDLG -#ifndef __DARWIN__ - #include "PLStringFuncs.h" -#endif +#include "wx/filedlg.h" -#if !USE_SHARED_LIBRARY -IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/dialog.h" #endif -// begin wxmac +#include "wx/tokenzr.h" +#include "wx/filename.h" #include "wx/mac/private.h" -#include - -#include "MoreFilesX.h" +#ifndef __DARWIN__ + #include + #include "PLStringFuncs.h" +#endif -extern bool gUseNavServices ; +IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) // the data we need to pass to our standard file hook routine // includes a pointer to the dialog, a pointer to the standard @@ -47,7 +40,8 @@ extern bool gUseNavServices ; // and a copy of the "previous" file spec of the reply record // so we can see if the selection has changed -struct OpenUserDataRec { +struct OpenUserDataRec +{ int currentfilter ; bool saveMode ; wxArrayString name ; @@ -60,41 +54,43 @@ struct OpenUserDataRec { typedef struct OpenUserDataRec OpenUserDataRec, *OpenUserDataRecPtr; -static pascal void NavEventProc( - NavEventCallbackMessage inSelector, - NavCBRecPtr ioParams, - NavCallBackUserData ioUserData); +static pascal void NavEventProc( + NavEventCallbackMessage inSelector, + NavCBRecPtr ioParams, + NavCallBackUserData ioUserData ); -static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); +static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); -static pascal void -NavEventProc( - NavEventCallbackMessage inSelector, - NavCBRecPtr ioParams, - NavCallBackUserData ioUserData ) +static pascal void NavEventProc( + NavEventCallbackMessage inSelector, + NavCBRecPtr ioParams, + NavCallBackUserData ioUserData ) { OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ; - if (inSelector == kNavCBEvent) { + if (inSelector == kNavCBEvent) + { } else if ( inSelector == kNavCBStart ) { - if (data && !(data->defaultLocation).IsEmpty()) + if (data && !(data->defaultLocation).empty()) { // 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)) + FSRef theFile; + wxMacPathToFSRef(data->defaultLocation, &theFile); + AEDesc theLocation = { typeNull, NULL }; + if (noErr == ::AECreateDesc(typeFSRef, &theFile, sizeof(FSRef), &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); + if( data->extensions.GetCount() > 0 ) + { + NavMenuItemSpec menuItem; + memset( &menuItem, 0, sizeof(menuItem) ); + menuItem.version = kNavMenuItemSpecVersion; + menuItem.menuType = data->currentfilter; + ::NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &menuItem); + } } else if ( inSelector == kNavCBPopupMenuSelect ) { @@ -107,15 +103,18 @@ NavEventProc( if ( data->saveMode ) { int i = menu->menuType ; - wxString extension = data->extensions[i].AfterLast('.') ; - extension.MakeLower() ; + + // isolate the first extension string + wxString firstExtension = data->extensions[i].BeforeFirst('|').BeforeFirst(';'); + + wxString extension = firstExtension.AfterLast('.') ; wxString sfilename ; wxMacCFStringHolder cfString( NavDialogGetSaveFileName( ioParams->context ) , false ); sfilename = cfString.AsString() ; int pos = sfilename.Find('.', true) ; - if ( pos != wxNOT_FOUND ) + if ( pos != wxNOT_FOUND && extension != wxT("*") ) { sfilename = sfilename.Left(pos+1)+extension ; cfString.Assign( sfilename , wxFONTENCODING_DEFAULT ) ; @@ -126,30 +125,33 @@ NavEventProc( } } - -void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) +void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) { myData->menuitems = NULL ; myData->currentfilter = 0 ; myData->saveMode = false ; - if ( filter && filter[0] ) + if ( !filter.empty() ) { wxString filter2(filter) ; int filterIndex = 0; bool isName = true ; wxString current ; - for( unsigned int i = 0; i < filter2.Len() ; i++ ) + + for ( unsigned int i = 0; i < filter2.length() ; i++ ) { - if( filter2.GetChar(i) == wxT('|') ) + if ( filter2.GetChar(i) == wxT('|') ) { - if( isName ) { + if ( isName ) + { myData->name.Add( current ) ; } - else { - myData->extensions.Add( current.MakeUpper() ) ; + else + { + myData->extensions.Add( current ) ; ++filterIndex ; } + isName = !isName ; current = wxEmptyString ; } @@ -162,38 +164,33 @@ void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) // 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() ) + if ( current.empty() ) myData->extensions.Add( myData->name[filterIndex] ) ; else - myData->extensions.Add( current.MakeUpper() ) ; + myData->extensions.Add( current ) ; if ( filterIndex == 0 || isName ) - myData->name.Add( current.MakeUpper() ) ; + myData->name.Add( current ) ; ++filterIndex ; const size_t extCount = myData->extensions.GetCount(); for ( size_t i = 0 ; i < extCount; i++ ) { - wxUint32 fileType; - wxUint32 creator; + wxUint32 fileType, creator; wxString extension = myData->extensions[i]; - if (extension.GetChar(0) == '*') - extension = extension.Mid(1); // Remove leading * + // Remove leading '*' + if (extension.length() && (extension.GetChar(0) == '*')) + extension = extension.Mid( 1 ); + + // Remove leading '.' + if (extension.length() && (extension.GetChar(0) == '.')) + extension = extension.Mid( 1 ); - if (extension.GetChar(0) == '.') - { - extension = extension.Mid(1); // Remove leading . - } - if (wxFileName::MacFindDefaultTypeAndCreator( extension, &fileType, &creator )) - { myData->filtermactypes.Add( (OSType)fileType ); - } else - { - myData->filtermactypes.Add( '****' ) ; // We'll fail safe if it's not recognized - } + myData->filtermactypes.Add( '****' ); // We'll fail safe if it's not recognized } } } @@ -215,98 +212,89 @@ static Boolean CheckFile( const wxString &filename , OSType type , OpenUserDataR return true ; wxStringTokenizer tokenizer( data->extensions[i] , wxT(";") ) ; - while( tokenizer.HasMoreTokens() ) + while ( tokenizer.HasMoreTokens() ) { wxString extension = tokenizer.GetNextToken() ; if ( extension.GetChar(0) == '*' ) extension = extension.Mid(1) ; + extension.MakeUpper(); - if ( file.Len() >= extension.Len() && extension == file.Right(extension.Len() ) ) + if ( file.length() >= extension.length() && extension == file.Right(extension.length() ) ) return true ; } } - return false ; - } - return true ; -} - -#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 ) - { - wxString file = wxMacMakeStringFromPascal( myCInfoPBPtr->hFileInfo.ioNamePtr ) ; - return !CheckFile( file , myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType , data ) ; + return false ; } - return false ; + return true ; } -#endif // end wxmac -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) +wxFileDialog::wxFileDialog( + wxWindow *parent, const wxString& message, + const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard, + long style, const wxPoint& pos, const wxSize& sz, const wxString& name) + : wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name) { wxASSERT_MSG( NavServicesAvailable() , wxT("Navigation Services are not running") ) ; } -pascal Boolean CrossPlatformFilterCallback ( +pascal Boolean CrossPlatformFilterCallback( AEDesc *theItem, void *info, void *callBackUD, - NavFilterModes filterMode -) + NavFilterModes filterMode ) { - bool display = true; OpenUserDataRecPtr data = (OpenUserDataRecPtr) callBackUD ; if (filterMode == kNavFilteringBrowserList) { + // We allow navigation to all folders. For files, we check against the current + // filter string. + // However, packages should be dealt with like files and not like folders. So + // check if a folder is a package before deciding what to do. NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*) info ; - if ( !theInfo->isFolder ) + FSRef fsref; + + if ( theInfo->isFolder ) { - 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 ) + // check bundle bit (using Finder Services - used by OS9 on some bundles) + FSCatalogInfo catalogInfo; + if (FSGetCatalogInfo (&fsref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL) != noErr) + return true; + + // Check bundle item (using Launch Services - used by OS-X through info.plist or APP) + LSItemInfoRecord lsInfo; + if (LSCopyItemInfoForRef(&fsref, kLSRequestBasicFlagsOnly, &lsInfo ) != noErr) + return true; + + // If it's not a bundle, then it's a normal folder and it passes our filter + FileInfo *fileInfo = (FileInfo *) catalogInfo.finderInfo; + if ( !(fileInfo->finderFlags & kHasBundle) && + !(lsInfo.flags & (kLSItemInfoIsApplication | kLSItemInfoIsPackage)) ) + return true; + } + else + { + AECoerceDesc (theItem, typeFSRef, theItem); + if ( AEGetDescData (theItem, &fsref, sizeof (FSRef)) == noErr) { - FSRef fsref ; - memcpy( &fsref , *theItem->dataHandle , sizeof(FSRef) ) ; wxString file = wxMacFSRefToPath( &fsref ) ; - display = CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + return CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; } } } - return display; + return true; } int wxFileDialog::ShowModal() { OSErr err; NavDialogCreationOptions dialogCreateOptions; + // set default options ::NavGetDefaultDialogCreationOptions(&dialogCreateOptions); @@ -322,7 +310,6 @@ int wxFileDialog::ShowModal() NavDialogRef dialog; NavObjectFilterUPP navFilterUPP = NULL; - CFArrayRef cfArray = NULL; // for popupExtension OpenUserDataRec myData; myData.defaultLocation = m_dir; @@ -341,48 +328,44 @@ int wxFileDialog::ShowModal() } } - if (m_dialogStyle & wxSAVE) + if (HasFdFlag(wxFD_SAVE)) { myData.saveMode = true; - if (!numFilters) - { - dialogCreateOptions.optionFlags |= kNavNoTypePopup; - } dialogCreateOptions.optionFlags |= kNavDontAutoTranslate; dialogCreateOptions.optionFlags |= kNavDontAddTranslateItems; + if (!numFilters) + dialogCreateOptions.optionFlags |= kNavNoTypePopup; // 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_windowStyle & wxFD_OVERWRITE_PROMPT)) + dialogCreateOptions.optionFlags |= kNavDontConfirmReplacement; + + err = ::NavCreatePutFileDialog( + &dialogCreateOptions, + kNavGenericSignature, // Suppresses the 'Default' (top) menu item + kNavGenericSignature, + sStandardNavEventFilter, + &myData, // for defaultLocation + &dialog ); } else { - - //let people select bundles/programs in dialogs + // let the user select bundles/programs in dialogs dialogCreateOptions.optionFlags |= kNavSupportPackages; - + navFilterUPP = NewNavObjectFilterUPP(CrossPlatformFilterCallback); - err = ::NavCreateGetFileDialog(&dialogCreateOptions, - NULL, // NavTypeListHandle - sStandardNavEventFilter, - NULL, // NavPreviewUPP - navFilterUPP, - (void *) &myData, // inClientData - &dialog); + err = ::NavCreateGetFileDialog( + &dialogCreateOptions, + NULL, // NavTypeListHandle + sStandardNavEventFilter, + NULL, // NavPreviewUPP + navFilterUPP, + (void *) &myData, // inClientData + &dialog ); } if (err == noErr) @@ -391,11 +374,12 @@ int wxFileDialog::ShowModal() // clean up filter related data, etc. if (navFilterUPP) ::DisposeNavObjectFilterUPP(navFilterUPP); - if (cfArray) - ::CFRelease(cfArray); if (err != noErr) + { + ::NavDialogDispose(dialog); return wxID_CANCEL; + } NavReplyRecord navReply; err = ::NavDialogGetReply(dialog, &navReply); @@ -406,40 +390,47 @@ int wxFileDialog::ShowModal() Size actualSize; FSRef theFSRef; wxString thePath ; - - m_filterIndex = myData.currentfilter ; - long count; - ::AECountItems(&navReply.selection , &count); + + m_filterIndex = myData.currentfilter; + ::AECountItems( &navReply.selection, &count ); for (long i = 1; i <= count; ++i) { - err = ::AEGetNthPtr(&(navReply.selection), i, typeFSRef, &theKeyword, &actualType, - &theFSRef, sizeof(theFSRef), &actualSize); + 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 ) ; + if (HasFdFlag(wxFD_SAVE)) + thePath = wxMacFSRefToPath( &theFSRef, navReply.saveFileName ); else - thePath = wxMacFSRefToPath( &theFSRef ) ; - + thePath = wxMacFSRefToPath( &theFSRef ); + if (!thePath) { ::NavDisposeReply(&navReply); + ::NavDialogDispose(dialog); return wxID_CANCEL; } + 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_fileName = wxFileNameFromPath(m_path); m_dir = wxPathOnly(m_path); } + ::NavDisposeReply(&navReply); + ::NavDialogDispose(dialog); return (err == noErr) ? wxID_OK : wxID_CANCEL; } +#endif // wxUSE_FILEDLG +