X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/489468feaa08b8f504735eecca522fb8d0f825d2..6178debcd342963974dbdce6ac2ddb2fbe89e42a:/src/osx/carbon/filedlg.cpp diff --git a/src/osx/carbon/filedlg.cpp b/src/osx/carbon/filedlg.cpp index 6e43845335..158846b529 100644 --- a/src/osx/carbon/filedlg.cpp +++ b/src/osx/carbon/filedlg.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/mac/carbon/filedlg.cpp +// Name: src/osx/carbon/filedlg.cpp // Purpose: wxFileDialog // Author: Stefan Csomor // Modified by: @@ -25,7 +25,7 @@ #include "wx/tokenzr.h" #include "wx/filename.h" -#include "wx/mac/private.h" +#include "wx/osx/private.h" #ifndef __DARWIN__ #include @@ -40,97 +40,241 @@ IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) // and a copy of the "previous" file spec of the reply record // so we can see if the selection has changed -struct OpenUserDataRec +class OpenUserDataRec { - int currentfilter ; - bool saveMode ; - wxArrayString name ; - wxArrayString extensions ; - wxArrayLong filtermactypes ; - wxString defaultLocation; - CFArrayRef menuitems ; +public: + OpenUserDataRec( wxFileDialog* dialog ); + + bool FilterCallback( AEDesc *theItem, void *info, NavFilterModes filterMode ); + void EventProc( NavEventCallbackMessage inSelector, NavCBRecPtr ioParams ); + + int GetCurrentFilter() const {return m_currentfilter;} + CFArrayRef GetMenuItems() const { return m_menuitems;} + + +private: + void EventProcCBEvent( NavCBRecPtr ioParams ); + void EventProcCBEventMouseDown( NavCBRecPtr ioParams); + void EventProcCBStart( NavCBRecPtr ioParams ); + void EventProcCBPopupMenuSelect( NavCBRecPtr ioParams ); + void EventProcCBCustomize( NavCBRecPtr ioParams ); + void EventProcCBAdjustRect( NavCBRecPtr ioParams ); + bool CheckFile( const wxString &filename , OSType type); + void MakeUserDataRec( const wxString& filter); + + wxFileDialog* m_dialog; + int m_currentfilter; + wxString m_defaultLocation; + wxArrayString m_extensions; + wxArrayLong m_filtermactypes; + CFMutableArrayRef m_menuitems; + wxArrayString m_name; + bool m_saveMode; + SInt16 m_lastRight; + SInt16 m_lastBottom; + bool m_controlAdded; }; -typedef struct OpenUserDataRec -OpenUserDataRec, *OpenUserDataRecPtr; - -static pascal void NavEventProc( - NavEventCallbackMessage inSelector, - NavCBRecPtr ioParams, - NavCallBackUserData ioUserData ); - -static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); +OpenUserDataRec::OpenUserDataRec( wxFileDialog* d) +{ + m_dialog = d; + m_controlAdded = false; + m_saveMode = m_dialog->HasFdFlag(wxFD_SAVE); + + m_defaultLocation = m_dialog->GetDirectory(); + MakeUserDataRec(m_dialog->GetWildcard()); + m_currentfilter = m_dialog->GetFilterIndex(); + + m_menuitems = NULL; + + size_t numFilters = m_extensions.GetCount(); + if (numFilters) + { + m_menuitems = CFArrayCreateMutable( kCFAllocatorDefault , + numFilters , &kCFTypeArrayCallBacks ) ; + for ( size_t i = 0 ; i < numFilters ; ++i ) + { + CFArrayAppendValue( m_menuitems , (CFStringRef) wxCFStringRef( m_name[i] ) ) ; + } + } + m_lastRight = m_lastBottom = 0; +} -static pascal void NavEventProc( - NavEventCallbackMessage inSelector, - NavCBRecPtr ioParams, - NavCallBackUserData ioUserData ) +void OpenUserDataRec::EventProc(NavEventCallbackMessage inSelector,NavCBRecPtr ioParams) { - OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ; - if (inSelector == kNavCBEvent) + switch (inSelector) { + case kNavCBEvent: + EventProcCBEvent(ioParams); + break; + case kNavCBStart: + EventProcCBStart(ioParams); + break; + case kNavCBPopupMenuSelect: + EventProcCBPopupMenuSelect(ioParams); + break; + case kNavCBCustomize: + EventProcCBCustomize(ioParams); + break; + case kNavCBAdjustRect: + EventProcCBAdjustRect(ioParams); + break; + default: + break; } - else if ( inSelector == kNavCBStart ) +} + +void OpenUserDataRec::EventProcCBEvent(NavCBRecPtr callBackParms) +{ + switch (callBackParms->eventData.eventDataParms.event->what) { - if (data && !(data->defaultLocation).empty()) + case mouseDown: { - // Set default location for the modern Navigation APIs - // Apple Technical Q&A 1151 - FSRef theFile; - wxMacPathToFSRef(data->defaultLocation, &theFile); - AEDesc theLocation = { typeNull, NULL }; - if (noErr == ::AECreateDesc(typeFSRef, &theFile, sizeof(FSRef), &theLocation)) - ::NavCustomControl(ioParams->context, kNavCtlSetLocation, (void *) &theLocation); + EventProcCBEventMouseDown(callBackParms); + break; } + } +} - if( data->extensions.GetCount() > 0 ) +void OpenUserDataRec::EventProcCBEventMouseDown(NavCBRecPtr callBackParms) +{ + EventRecord *evt = callBackParms->eventData.eventDataParms.event; + Point where = evt->where; + QDGlobalToLocalPoint(GetWindowPort(callBackParms->window), &where); + + ControlRef whichControl = FindControlUnderMouse(where, callBackParms->window, NULL); + if (whichControl != NULL) + { + ControlKind theKind; + GetControlKind(whichControl, &theKind); + + // Moving the focus if we clicked in an focusable control + if ((theKind.kind == kControlKindEditUnicodeText) || + (theKind.kind == kControlKindEditText) || + (theKind.kind == kControlKindDataBrowser) || + (theKind.kind == kControlKindListBox)) { - NavMenuItemSpec menuItem; - memset( &menuItem, 0, sizeof(menuItem) ); - menuItem.version = kNavMenuItemSpecVersion; - menuItem.menuType = data->currentfilter; - ::NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &menuItem); + ControlRef currentlyFocusedControl; + GetKeyboardFocus(callBackParms->window, ¤tlyFocusedControl); + if (currentlyFocusedControl != whichControl) + SetKeyboardFocus(callBackParms->window, whichControl, kControlFocusNextPart); } + HandleControlClick(whichControl, where, evt->modifiers, NULL); } - else if ( inSelector == kNavCBPopupMenuSelect ) +} + +void OpenUserDataRec::EventProcCBStart(NavCBRecPtr ioParams) +{ + if (!m_defaultLocation.empty()) { - NavMenuItemSpec * menu = (NavMenuItemSpec *) ioParams->eventData.eventDataParms.param ; - const size_t numFilters = data->extensions.GetCount(); + // Set default location for the modern Navigation APIs + // Apple Technical Q&A 1151 + FSRef theFile; + wxMacPathToFSRef(m_defaultLocation, &theFile); + AEDesc theLocation = { typeNull, NULL }; + if (noErr == ::AECreateDesc(typeFSRef, &theFile, sizeof(FSRef), &theLocation)) + ::NavCustomControl(ioParams->context, kNavCtlSetLocation, (void *) &theLocation); + } + + if( m_extensions.GetCount() > 0 ) + { + NavMenuItemSpec menuItem; + memset( &menuItem, 0, sizeof(menuItem) ); + menuItem.version = kNavMenuItemSpecVersion; + menuItem.menuType = m_currentfilter; + ::NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &menuItem); + } + + if (m_dialog->GetExtraControl()) + { + m_controlAdded = true; + ControlRef ref = m_dialog->GetExtraControl()->GetPeer()->GetControlRef(); + NavCustomControl(ioParams->context, kNavCtlAddControl, ref); + } + +} - if ( menu->menuType < numFilters ) +void OpenUserDataRec::EventProcCBPopupMenuSelect(NavCBRecPtr ioParams) +{ + NavMenuItemSpec * menu = (NavMenuItemSpec *) ioParams->eventData.eventDataParms.param ; + const size_t numFilters = m_extensions.GetCount(); + + if ( menu->menuType < numFilters ) + { + m_currentfilter = menu->menuType ; + if ( m_saveMode ) { - data->currentfilter = menu->menuType ; - if ( data->saveMode ) + int i = menu->menuType ; + + // isolate the first extension string + wxString firstExtension = m_extensions[i].BeforeFirst('|').BeforeFirst(';'); + + wxString extension = firstExtension.AfterLast('.') ; + wxString sfilename ; + + wxCFStringRef cfString( wxCFRetain( NavDialogGetSaveFileName( ioParams->context ) ) ); + sfilename = cfString.AsString() ; + + int pos = sfilename.Find('.', true) ; + if ( pos != wxNOT_FOUND && extension != wxT("*") ) { - int i = menu->menuType ; - - // isolate the first extension string - wxString firstExtension = data->extensions[i].BeforeFirst('|').BeforeFirst(';'); - - wxString extension = firstExtension.AfterLast('.') ; - wxString sfilename ; - - wxCFStringRef cfString( wxCFRetain( NavDialogGetSaveFileName( ioParams->context ) ) ); - sfilename = cfString.AsString() ; + sfilename = sfilename.Left(pos+1)+extension ; + cfString = wxCFStringRef( sfilename , wxFONTENCODING_DEFAULT ) ; + NavDialogSetSaveFileName( ioParams->context , cfString ) ; + } + } + } +} - int pos = sfilename.Find('.', true) ; - if ( pos != wxNOT_FOUND && extension != wxT("*") ) - { - sfilename = sfilename.Left(pos+1)+extension ; - cfString = wxCFStringRef( sfilename , wxFONTENCODING_DEFAULT ) ; - NavDialogSetSaveFileName( ioParams->context , cfString ) ; - } +void OpenUserDataRec::EventProcCBCustomize(NavCBRecPtr ioParams) +{ + wxWindow* control = m_dialog->GetExtraControl(); + + if ( control ) + { + SInt16 neededRight, neededBottom; + + wxSize size = m_dialog->GetExtraControl()->GetSize(); + neededRight = ioParams->customRect.left + size.x; + neededBottom = ioParams->customRect.top + size.y; + + if (ioParams->customRect.right == 0 && ioParams->customRect.bottom == 0) + { + ioParams->customRect.right = neededRight; + ioParams->customRect.bottom = neededBottom; + } + else + { + if ( ioParams->customRect.right != m_lastRight ) + { + if ( ioParams->customRect.right < neededRight ) + ioParams->customRect.right = neededRight; + } + if ( ioParams->customRect.bottom != m_lastBottom ) + { + if ( ioParams->customRect.bottom < neededBottom ) + ioParams->customRect.bottom = neededBottom; } } + m_lastRight = ioParams->customRect.right; + m_lastBottom = ioParams->customRect.bottom; } } -void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) +void OpenUserDataRec::EventProcCBAdjustRect(NavCBRecPtr ioParams) { - myData->menuitems = NULL ; - myData->currentfilter = 0 ; - myData->saveMode = false ; + wxWindow* control = m_dialog->GetExtraControl(); + + if ( control && m_controlAdded) + { + control->SetSize(ioParams->customRect.left , ioParams->customRect.top, + ioParams->customRect.right - ioParams->customRect.left, + ioParams->customRect.bottom - ioParams->customRect.top); + } +} +void OpenUserDataRec::MakeUserDataRec( const wxString& filter ) +{ if ( !filter.empty() ) { wxString filter2(filter) ; @@ -144,11 +288,11 @@ void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) { if ( isName ) { - myData->name.Add( current ) ; + m_name.Add( current ) ; } else { - myData->extensions.Add( current ) ; + m_extensions.Add( current ) ; ++filterIndex ; } @@ -165,19 +309,19 @@ void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) wxASSERT_MSG( filterIndex == 0 || !isName , wxT("incorrect format of format string") ) ; if ( current.empty() ) - myData->extensions.Add( myData->name[filterIndex] ) ; + m_extensions.Add( m_name[filterIndex] ) ; else - myData->extensions.Add( current ) ; + m_extensions.Add( current ) ; if ( filterIndex == 0 || isName ) - myData->name.Add( current ) ; + m_name.Add( current ) ; ++filterIndex ; - const size_t extCount = myData->extensions.GetCount(); + const size_t extCount = m_extensions.GetCount(); for ( size_t i = 0 ; i < extCount; i++ ) { wxUint32 fileType, creator; - wxString extension = myData->extensions[i]; + wxString extension = m_extensions[i]; // Remove leading '*' if (extension.length() && (extension.GetChar(0) == '*')) @@ -188,30 +332,30 @@ void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) extension = extension.Mid( 1 ); if (wxFileName::MacFindDefaultTypeAndCreator( extension, &fileType, &creator )) - myData->filtermactypes.Add( (OSType)fileType ); + m_filtermactypes.Add( (OSType)fileType ); else - myData->filtermactypes.Add( '****' ); // We'll fail safe if it's not recognized + m_filtermactypes.Add( '****' ); // We'll fail safe if it's not recognized } } } -static Boolean CheckFile( const wxString &filename , OSType type , OpenUserDataRecPtr data) +bool OpenUserDataRec::CheckFile( const wxString &filename , OSType type) { wxString file(filename) ; file.MakeUpper() ; - if ( data->extensions.GetCount() > 0 ) + if ( m_extensions.GetCount() > 0 ) { //for ( int i = 0 ; i < data->numfilters ; ++i ) - int i = data->currentfilter ; - if ( data->extensions[i].Right(2) == wxT(".*") ) + int i = m_currentfilter ; + if ( m_extensions[i].Right(2) == wxT(".*") ) return true ; { - if ( type == (OSType)data->filtermactypes[i] ) + if ( type == (OSType)m_filtermactypes[i] ) return true ; - wxStringTokenizer tokenizer( data->extensions[i] , wxT(";") ) ; + wxStringTokenizer tokenizer( m_extensions[i] , wxT(";") ) ; while ( tokenizer.HasMoreTokens() ) { wxString extension = tokenizer.GetNextToken() ; @@ -230,25 +374,11 @@ static Boolean CheckFile( const wxString &filename , OSType type , OpenUserDataR return true ; } -// end wxmac - -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( - AEDesc *theItem, - void *info, - void *callBackUD, - NavFilterModes filterMode ) +bool OpenUserDataRec::FilterCallback( + AEDesc *theItem, + void *info, + NavFilterModes filterMode ) { - OpenUserDataRecPtr data = (OpenUserDataRecPtr) callBackUD ; - if (filterMode == kNavFilteringBrowserList) { // We allow navigation to all folders. For files, we check against the current @@ -257,23 +387,23 @@ pascal Boolean CrossPlatformFilterCallback( // check if a folder is a package before deciding what to do. NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*) info ; FSRef fsref; - + if ( theInfo->isFolder ) { // 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)) ) + !(lsInfo.flags & (kLSItemInfoIsApplication | kLSItemInfoIsPackage)) ) return true; } else @@ -282,16 +412,73 @@ pascal Boolean CrossPlatformFilterCallback( if ( AEGetDescData (theItem, &fsref, sizeof (FSRef)) == noErr) { wxString file = wxMacFSRefToPath( &fsref ) ; - return CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + return CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType ) ; } } } - + return true; } +// end wxmac + +pascal Boolean CrossPlatformFilterCallback( + AEDesc *theItem, + void *info, + void *callBackUD, + NavFilterModes filterMode ); + +pascal Boolean CrossPlatformFilterCallback( + AEDesc *theItem, + void *info, + void *callBackUD, + NavFilterModes filterMode ) +{ + OpenUserDataRec* data = (OpenUserDataRec*) callBackUD ; + return data->FilterCallback(theItem,info,filterMode); +} + +static pascal void NavEventProc( + NavEventCallbackMessage inSelector, + NavCBRecPtr ioParams, + NavCallBackUserData ioUserData ); + +static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); + +static pascal void NavEventProc( + NavEventCallbackMessage inSelector, + NavCBRecPtr ioParams, + NavCallBackUserData ioUserData ) +{ + OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ; + data->EventProc(inSelector, ioParams); +} + + +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") ) ; +} + +void wxFileDialog::SetupExtraControls(WXWindow nativeWindow) +{ + wxTopLevelWindow::Create( GetParent(), nativeWindow ); + + if (HasExtraControlCreator()) + { + CreateExtraControl(); + } +} + int wxFileDialog::ShowModal() { + m_paths.Empty(); + m_fileNames.Empty(); + OSErr err; NavDialogCreationOptions dialogCreateOptions; @@ -307,38 +494,21 @@ int wxFileDialog::ShowModal() wxCFStringRef defaultFileName(m_fileName, GetFont().GetEncoding()); dialogCreateOptions.saveFileName = defaultFileName; - NavDialogRef dialog; NavObjectFilterUPP navFilterUPP = NULL; - 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) wxCFStringRef( myData.name[i] , GetFont().GetEncoding() ) ) ; - } - } - + OpenUserDataRec myData( this ); + + dialogCreateOptions.popupExtension = myData.GetMenuItems(); + if (HasFdFlag(wxFD_SAVE)) { - myData.saveMode = true; - dialogCreateOptions.optionFlags |= kNavDontAutoTranslate; dialogCreateOptions.optionFlags |= kNavDontAddTranslateItems; - if (!numFilters) + if (dialogCreateOptions.popupExtension == NULL) dialogCreateOptions.optionFlags |= kNavNoTypePopup; // The extension is important - if (numFilters < 2) + if ( dialogCreateOptions.popupExtension == NULL || CFArrayGetCount(dialogCreateOptions.popupExtension)<2) dialogCreateOptions.optionFlags |= kNavPreserveSaveFileExtension; if (!(m_windowStyle & wxFD_OVERWRITE_PROMPT)) @@ -367,9 +537,15 @@ int wxFileDialog::ShowModal() (void *) &myData, // inClientData &dialog ); } - + + SetupExtraControls(NavDialogGetWindow(dialog)); + if (err == noErr) + { + wxDialog::OSXBeginModalDialog(); err = ::NavDialogRun(dialog); + wxDialog::OSXEndModalDialog(); + } // clean up filter related data, etc. if (navFilterUPP) @@ -392,7 +568,7 @@ int wxFileDialog::ShowModal() wxString thePath ; long count; - m_filterIndex = myData.currentfilter; + m_filterIndex = myData.GetCurrentFilter(); ::AECountItems( &navReply.selection, &count ); for (long i = 1; i <= count; ++i) { @@ -432,5 +608,10 @@ int wxFileDialog::ShowModal() return (err == noErr) ? wxID_OK : wxID_CANCEL; } +bool wxFileDialog::SupportsExtraControl() const +{ + return true; +} + #endif // wxUSE_FILEDLG