mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-30 23:59:41 +02:00
Now we know why the "automatically add extension" stuff was commented on in the FileDialog at least. :-)
796 lines
24 KiB
C++
796 lines
24 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: filedlg.cpp
|
|
// Purpose: wxFileDialog
|
|
// Author: Stefan Csomor
|
|
// Modified by: Leland Lucius
|
|
// Created: 1998-01-01
|
|
// RCS-ID: $Id: FileDialogPrivate.cpp,v 1.6 2009-07-26 08:58:50 llucius Exp $
|
|
// Copyright: (c) Stefan Csomor
|
|
// Licence: wxWindows licence
|
|
//
|
|
// Modified for Audacity to support an additional button on Save dialogs
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#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"
|
|
|
|
#include "../FileDialog.h"
|
|
|
|
#ifndef __DARWIN__
|
|
#include "PLStringFuncs.h"
|
|
#endif
|
|
|
|
IMPLEMENT_CLASS(FileDialog, wxFileDialogBase)
|
|
|
|
// begin wxmac
|
|
|
|
#include "wx/mac/private.h"
|
|
|
|
#ifndef __DARWIN__
|
|
#include <Navigation.h>
|
|
#endif
|
|
|
|
extern bool gUseNavServices ;
|
|
|
|
#define kCustom 'cstm'
|
|
#define kChoice 1
|
|
#define kButton 2
|
|
|
|
static ControlID kChoiceID = { kCustom, kChoice };
|
|
static ControlID kButtonID = { kCustom, kButton };
|
|
|
|
// the data we need to pass to our standard file hook routine
|
|
// includes a pointer to the dialog, a pointer to the standard
|
|
// file reply record (so we can inspect the current selection)
|
|
// and a copy of the "previous" file spec of the reply record
|
|
// so we can see if the selection has changed
|
|
|
|
struct CustomData {
|
|
FileDialog *me;
|
|
NavDialogRef context;
|
|
WindowRef window;
|
|
Rect bounds;
|
|
ControlRef userpane;
|
|
ControlRef choice;
|
|
ControlRef button;
|
|
MenuRef menu;
|
|
wxArrayString name;
|
|
wxArrayString extensions;
|
|
wxArrayLong filtermactypes;
|
|
wxString defaultLocation;
|
|
int currentfilter;
|
|
bool saveMode;
|
|
bool showing;
|
|
};
|
|
|
|
typedef struct CustomData
|
|
CustomData, *CustomDataPtr;
|
|
|
|
static pascal void NavEventProc(
|
|
NavEventCallbackMessage inSelector,
|
|
NavCBRecPtr ioParams,
|
|
NavCallBackUserData ioUserData);
|
|
|
|
static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc);
|
|
|
|
static void HandleAdjustRect(NavCBRecPtr callBackParms, CustomData * data)
|
|
{
|
|
Rect rect;
|
|
|
|
if (!data->userpane)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetControlBounds(data->userpane, &rect);
|
|
|
|
SInt16 w = rect.right - rect.left;
|
|
SInt16 h = rect.bottom - rect.top;
|
|
SInt16 cw = callBackParms->customRect.right - callBackParms->customRect.left;
|
|
SInt16 ch = callBackParms->customRect.bottom - callBackParms->customRect.top;
|
|
|
|
MoveControl(data->userpane,
|
|
callBackParms->customRect.left + ((cw-w) / 2),
|
|
callBackParms->customRect.top + ((ch-h) / 2));
|
|
|
|
return;
|
|
}
|
|
|
|
static void HandleCarbonCustomizeEvent(NavCBRecPtr callBackParms, CustomData * data)
|
|
{
|
|
if ((callBackParms->customRect.right == 0) && (callBackParms->customRect.bottom == 0))
|
|
{
|
|
callBackParms->customRect.right = callBackParms->customRect.left +
|
|
(data->bounds.right - data->bounds.left);
|
|
callBackParms->customRect.bottom = callBackParms->customRect.top +
|
|
(data->bounds.bottom - data->bounds.top);
|
|
}
|
|
}
|
|
|
|
static void HandleCustomMouseDown(NavCBRecPtr callBackParms, CustomData *data)
|
|
{
|
|
EventRecord *evt = callBackParms->eventData.eventDataParms.event;
|
|
Point where = evt->where;
|
|
|
|
GlobalToLocal(&where);
|
|
|
|
ControlRef control = FindControlUnderMouse(where, callBackParms->window, NULL);
|
|
if (control != NULL)
|
|
{
|
|
HandleControlClick(control, where, evt->modifiers, (ControlActionUPP)-1L);
|
|
NavCustomControl(callBackParms->context, kNavCtlBrowserRedraw, NULL);
|
|
}
|
|
}
|
|
|
|
static void HandleNormalEvents(NavCBRecPtr callBackParms, CustomData *data)
|
|
{
|
|
switch (callBackParms->eventData.eventDataParms.event->what)
|
|
{
|
|
case mouseDown:
|
|
{
|
|
HandleCustomMouseDown(callBackParms, data);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const EventTypeSpec namedAttrsList[] =
|
|
{
|
|
{ kEventClassAccessibility , kEventAccessibleGetNamedAttribute },
|
|
{ kEventClassControl , kEventControlHit },
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
static OSStatus SetElement(wxMacCarbonEvent & event, HIObjectRef objectRef,
|
|
UInt64 id, int parm)
|
|
{
|
|
OSStatus result = eventNotHandledErr;
|
|
AXUIElementRef elem;
|
|
|
|
elem = AXUIElementCreateWithHIObjectAndIdentifier(objectRef, id);
|
|
if (elem)
|
|
{
|
|
result = event.SetParameter(parm,
|
|
typeCFTypeRef,
|
|
sizeof(elem),
|
|
&elem);
|
|
CFRelease(elem);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static pascal OSStatus HandlePaneEvents(EventHandlerCallRef handlerRef, EventRef eventRef, void *data)
|
|
{
|
|
wxMacCarbonEvent event(eventRef);
|
|
CustomData *dt = (CustomData *) data;
|
|
OSStatus result = eventNotHandledErr;
|
|
|
|
switch (event.GetClass())
|
|
{
|
|
case kEventClassControl:
|
|
{
|
|
ControlRef control;
|
|
ControlID cid;
|
|
|
|
control = event.GetParameter<ControlRef>(kEventParamDirectObject, typeControlRef);
|
|
if (control == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
GetControlID(control, &cid);
|
|
if (cid.signature != kCustom)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch (cid.id)
|
|
{
|
|
case kChoice:
|
|
{
|
|
MenuRef menu = GetControlPopupMenuRef(control);
|
|
UInt32 v = GetControl32BitValue(control) - 1;
|
|
const size_t numFilters = dt->extensions.GetCount();
|
|
|
|
if (v < (UInt32) dt->extensions.GetCount())
|
|
{
|
|
dt->currentfilter = v;
|
|
|
|
NavCustomControl(dt->context, kNavCtlBrowserRedraw, NULL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kButton:
|
|
{
|
|
dt->me->ClickButton(GetControl32BitValue(dt->choice) - 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kEventClassAccessibility:
|
|
{
|
|
switch (event.GetKind())
|
|
{
|
|
case kEventAccessibleGetNamedAttribute:
|
|
{
|
|
CFStringRef attr;
|
|
|
|
require_noerr(event.GetParameter(kEventParamAccessibleAttributeName,
|
|
typeCFTypeRef,
|
|
sizeof(attr),
|
|
&attr), ParameterError);
|
|
|
|
if (false)
|
|
{
|
|
}
|
|
else if (CFStringCompare(attr, kAXRoleAttribute, 0) == kCFCompareEqualTo)
|
|
{
|
|
CFStringRef role = kAXGroupRole;
|
|
|
|
result = event.SetParameter(kEventParamAccessibleAttributeValue,
|
|
typeCFStringRef,
|
|
sizeof(role),
|
|
&role);
|
|
|
|
require_noerr(result, ParameterError);
|
|
}
|
|
else if (CFStringCompare(attr, kAXRoleDescriptionAttribute, 0) == kCFCompareEqualTo)
|
|
{
|
|
CFStringRef role = kAXGroupRole;
|
|
CFStringRef desc;
|
|
|
|
desc = HICopyAccessibilityRoleDescription(role, NULL);
|
|
if (desc)
|
|
{
|
|
result = event.SetParameter(kEventParamAccessibleAttributeValue,
|
|
typeCFStringRef,
|
|
sizeof(desc),
|
|
&desc);
|
|
|
|
CFRelease(desc);
|
|
|
|
require_noerr(result, ParameterError);
|
|
}
|
|
}
|
|
else if (CFStringCompare(attr, kAXParentAttribute, 0) == kCFCompareEqualTo)
|
|
{
|
|
HIViewRef viewRef = HIViewGetSuperview(dt->userpane);
|
|
if (viewRef)
|
|
{
|
|
result = SetElement(event, (HIObjectRef) viewRef, 0,
|
|
kEventParamAccessibleAttributeValue);
|
|
|
|
require_noerr(result, ParameterError);
|
|
}
|
|
}
|
|
else if (CFStringCompare(attr, kAXWindowAttribute, 0) == kCFCompareEqualTo)
|
|
{
|
|
WindowRef winRef = HIViewGetWindow((HIViewRef) dt->userpane);
|
|
|
|
if (winRef)
|
|
{
|
|
result = SetElement(event, (HIObjectRef) winRef, 0,
|
|
kEventParamAccessibleAttributeValue);
|
|
|
|
require_noerr(result, ParameterError);
|
|
}
|
|
}
|
|
else if (CFStringCompare(attr, kAXTopLevelUIElementAttribute, 0) == kCFCompareEqualTo)
|
|
{
|
|
if (dt->window)
|
|
{
|
|
result = SetElement(event, (HIObjectRef) dt->window, 0,
|
|
kEventParamAccessibleAttributeValue);
|
|
|
|
require_noerr(result, ParameterError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = eventNotHandledErr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
ParameterError:
|
|
return result;
|
|
}
|
|
|
|
DEFINE_ONE_SHOT_HANDLER_GETTER(HandlePaneEvents);
|
|
|
|
static void HandleStartEvent(NavCBRecPtr callBackParms, CustomData *data)
|
|
{
|
|
data->context = callBackParms->context;
|
|
|
|
CreateUserPaneControl(callBackParms->window, &data->bounds, kControlSupportsEmbedding, &data->userpane);
|
|
|
|
InstallControlEventHandler(data->userpane,
|
|
GetHandlePaneEventsUPP(),
|
|
GetEventTypeCount(namedAttrsList),
|
|
namedAttrsList,
|
|
data,
|
|
NULL);
|
|
|
|
EmbedControl(data->choice, data->userpane);
|
|
EmbedControl(data->button, data->userpane);
|
|
|
|
NavCustomControl(callBackParms->context, kNavCtlAddControl, data->userpane);
|
|
|
|
HandleAdjustRect(callBackParms, data);
|
|
|
|
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(callBackParms->context, kNavCtlSetLocation, (void *) &theLocation);
|
|
}
|
|
}
|
|
|
|
static pascal void NavEventProc(NavEventCallbackMessage inSelector,
|
|
NavCBRecPtr ioParams,
|
|
NavCallBackUserData ioUserData)
|
|
{
|
|
CustomData * data = (CustomData *) ioUserData ;
|
|
|
|
switch (inSelector)
|
|
{
|
|
case kNavCBCustomize:
|
|
{
|
|
HandleCarbonCustomizeEvent(ioParams, data);
|
|
break;
|
|
}
|
|
|
|
case kNavCBStart:
|
|
{
|
|
HandleStartEvent(ioParams, data);
|
|
break;
|
|
}
|
|
|
|
case kNavCBAdjustRect:
|
|
{
|
|
HandleAdjustRect(ioParams, data);
|
|
break;
|
|
}
|
|
|
|
case kNavCBEvent:
|
|
{
|
|
HandleNormalEvents(ioParams, data);
|
|
break;
|
|
}
|
|
|
|
case kNavCBTerminate:
|
|
{
|
|
data->showing = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void MakeUserDataRec(CustomData *myData, const wxString& filter)
|
|
{
|
|
myData->currentfilter = 0 ;
|
|
|
|
if (!filter.IsEmpty())
|
|
{
|
|
wxString filter2(filter) ;
|
|
int filterIndex = 0;
|
|
bool isName = true ;
|
|
wxString current ;
|
|
for( unsigned int i = 0; i < filter2.Len() ; i++ )
|
|
{
|
|
if( filter2.GetChar(i) == wxT('|') )
|
|
{
|
|
if( isName )
|
|
{
|
|
myData->name.Add( current ) ;
|
|
}
|
|
else
|
|
{
|
|
myData->extensions.Add( current.MakeUpper() ) ;
|
|
++filterIndex ;
|
|
}
|
|
isName = !isName ;
|
|
current = wxEmptyString ;
|
|
}
|
|
else
|
|
{
|
|
current += filter2.GetChar(i) ;
|
|
}
|
|
}
|
|
// 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] ) ;
|
|
else
|
|
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++ )
|
|
{
|
|
wxUint32 fileType;
|
|
wxUint32 creator;
|
|
wxString extension = myData->extensions[i];
|
|
|
|
if (extension.GetChar(0) == '*')
|
|
extension = extension.Mid(1); // Remove leading *
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean CheckFile( const wxString &filename , OSType type , CustomDataPtr data)
|
|
{
|
|
wxString file(filename) ;
|
|
file.MakeUpper() ;
|
|
|
|
if ( data->extensions.GetCount() > 0 )
|
|
{
|
|
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 ;
|
|
}
|
|
}
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
// end wxmac
|
|
|
|
FileDialog::FileDialog(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_callback = NULL;
|
|
m_cbdata = NULL;
|
|
m_dialogStyle = style;
|
|
}
|
|
|
|
static pascal Boolean CrossPlatformFilterCallback (
|
|
AEDesc *theItem,
|
|
void *info,
|
|
void *callBackUD,
|
|
NavFilterModes filterMode
|
|
)
|
|
{
|
|
bool display = true;
|
|
CustomDataPtr data = (CustomDataPtr) callBackUD ;
|
|
|
|
if (filterMode == kNavFilteringBrowserList)
|
|
{
|
|
NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*) info ;
|
|
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 )
|
|
{
|
|
FSRef fsref ;
|
|
memcpy( &fsref , *theItem->dataHandle , sizeof(FSRef) ) ;
|
|
wxString file = wxMacFSRefToPath( &fsref ) ;
|
|
display = CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return display;
|
|
}
|
|
|
|
int FileDialog::ShowModal()
|
|
{
|
|
OSErr err;
|
|
NavDialogCreationOptions dialogCreateOptions;
|
|
// set default options
|
|
::NavGetDefaultDialogCreationOptions(&dialogCreateOptions);
|
|
|
|
// this was always unset in the old code
|
|
dialogCreateOptions.optionFlags &= ~kNavSelectDefaultLocation;
|
|
|
|
wxMacCFStringHolder message(m_message, GetFont().GetEncoding());
|
|
dialogCreateOptions.windowTitle = message;
|
|
|
|
wxMacCFStringHolder defaultFileName(m_fileName, GetFont().GetEncoding());
|
|
dialogCreateOptions.saveFileName = defaultFileName;
|
|
|
|
NavDialogRef dialog;
|
|
NavObjectFilterUPP navFilterUPP = NULL;
|
|
CustomData myData;
|
|
|
|
SetRect(&myData.bounds, 0, 0, 0, 0);
|
|
myData.me = this;
|
|
myData.window = NULL;
|
|
myData.defaultLocation = m_dir;
|
|
myData.userpane = NULL;
|
|
myData.choice = NULL;
|
|
myData.button = NULL;
|
|
myData.saveMode = false;
|
|
myData.showing = true;
|
|
|
|
Rect r;
|
|
SInt16 base;
|
|
SInt16 margin = 3;
|
|
SInt16 gap = 0;
|
|
|
|
MakeUserDataRec(&myData , m_wildCard);
|
|
myData.currentfilter = m_filterIndex;
|
|
size_t numFilters = myData.extensions.GetCount();
|
|
if (numFilters)
|
|
{
|
|
CreateNewMenu(0, 0, &myData.menu);
|
|
|
|
for ( size_t i = 0 ; i < numFilters ; ++i )
|
|
{
|
|
::AppendMenuItemTextWithCFString(myData.menu,
|
|
wxMacCFStringHolder(myData.name[i],
|
|
GetFont().GetEncoding()),
|
|
4,
|
|
i,
|
|
NULL);
|
|
}
|
|
|
|
SetRect(&r, 0, margin, 0, 0);
|
|
CreatePopupButtonControl(NULL, &r, CFSTR("Format:"), -12345, true, -1, teJustLeft, normal, &myData.choice);
|
|
SetControlID(myData.choice, &kChoiceID);
|
|
SetControlPopupMenuRef(myData.choice, myData.menu);
|
|
SetControl32BitMinimum(myData.choice, 1);
|
|
SetControl32BitMaximum(myData.choice, myData.name.GetCount());
|
|
SetControl32BitValue(myData.choice, myData.currentfilter + 1);
|
|
GetBestControlRect(myData.choice, &r, &base);
|
|
SizeControl(myData.choice, r.right - r.left, r.bottom - r.top);
|
|
UnionRect(&myData.bounds, &r, &myData.bounds);
|
|
gap = 15;
|
|
|
|
HIObjectSetAuxiliaryAccessibilityAttribute((HIObjectRef)myData.choice, 0, kAXDescriptionAttribute, CFSTR("Format"));
|
|
}
|
|
|
|
if (!m_buttonlabel.IsEmpty())
|
|
{
|
|
wxMacCFStringHolder cfString(wxStripMenuCodes(m_buttonlabel).c_str(), wxFONTENCODING_DEFAULT);
|
|
SetRect(&r, myData.bounds.right + gap, margin, 0, 0);
|
|
CreatePushButtonControl(NULL, &r, cfString, &myData.button);
|
|
SetControlID(myData.button, &kButtonID);
|
|
GetBestControlRect(myData.button, &r, &base);
|
|
SizeControl(myData.button, r.right - r.left, r.bottom - r.top);
|
|
UnionRect(&myData.bounds, &r, &myData.bounds);
|
|
}
|
|
|
|
// Expand bounding rectangle to include a top and bottom margin
|
|
myData.bounds.top -= margin;
|
|
myData.bounds.bottom += margin;
|
|
|
|
dialogCreateOptions.optionFlags |= kNavNoTypePopup;
|
|
|
|
if (m_dialogStyle & wxFD_SAVE)
|
|
{
|
|
dialogCreateOptions.modality = kWindowModalityWindowModal;
|
|
dialogCreateOptions.parentWindow = (WindowRef) GetParent()->MacGetTopLevelWindowRef();
|
|
|
|
myData.saveMode = true;
|
|
|
|
if (!numFilters)
|
|
{
|
|
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 & wxFD_OVERWRITE_PROMPT))
|
|
{
|
|
dialogCreateOptions.optionFlags |= kNavDontConfirmReplacement;
|
|
}
|
|
#endif
|
|
|
|
err = ::NavCreatePutFileDialog(&dialogCreateOptions,
|
|
// Suppresses the 'Default' (top) menu item
|
|
kNavGenericSignature, kNavGenericSignature,
|
|
sStandardNavEventFilter,
|
|
&myData, // for defaultLocation
|
|
&dialog);
|
|
}
|
|
else
|
|
{
|
|
|
|
//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);
|
|
}
|
|
|
|
if (err == noErr)
|
|
err = ::NavDialogRun(dialog);
|
|
|
|
if (err == noErr)
|
|
{
|
|
myData.window = NavDialogGetWindow(dialog);
|
|
Rect r;
|
|
|
|
// This creates our "fake" dialog with the same dimensions as the sheet so
|
|
// that Options dialogs will center properly on the sheet. The "fake" dialog
|
|
// is never actually seen.
|
|
GetWindowBounds(myData.window, kWindowStructureRgn, &r);
|
|
wxDialog::Create(NULL, // no parent...otherwise strange things happen
|
|
wxID_ANY,
|
|
wxEmptyString,
|
|
wxPoint(r.left, r.top),
|
|
wxSize(r.right - r.left, r.bottom - r.top));
|
|
|
|
BeginAppModalStateForWindow(myData.window);
|
|
|
|
while (myData.showing)
|
|
{
|
|
wxTheApp->MacDoOneEvent();
|
|
}
|
|
|
|
EndAppModalStateForWindow(myData.window);
|
|
}
|
|
|
|
// clean up filter related data, etc.
|
|
if (navFilterUPP)
|
|
::DisposeNavObjectFilterUPP(navFilterUPP);
|
|
|
|
if (err != noErr)
|
|
return wxID_CANCEL;
|
|
|
|
NavReplyRecord navReply;
|
|
err = ::NavDialogGetReply(dialog, &navReply);
|
|
if (err == noErr && navReply.validRecord)
|
|
{
|
|
AEKeyword theKeyword;
|
|
DescType actualType;
|
|
Size actualSize;
|
|
FSRef theFSRef;
|
|
wxString thePath ;
|
|
|
|
m_filterIndex = myData.currentfilter;
|
|
|
|
long count;
|
|
::AECountItems(&navReply.selection , &count);
|
|
for (long i = 1; i <= count; ++i)
|
|
{
|
|
err = ::AEGetNthPtr(&(navReply.selection), i, typeFSRef, &theKeyword, &actualType,
|
|
&theFSRef, sizeof(theFSRef), &actualSize);
|
|
if (err != noErr)
|
|
break;
|
|
|
|
if (m_dialogStyle & wxFD_SAVE)
|
|
thePath = wxMacFSRefToPath( &theFSRef , navReply.saveFileName ) ;
|
|
else
|
|
thePath = wxMacFSRefToPath( &theFSRef ) ;
|
|
|
|
if (!thePath)
|
|
{
|
|
::NavDisposeReply(&navReply);
|
|
return wxID_CANCEL;
|
|
}
|
|
|
|
wxFileName fn = ConvertSlashInFileName(thePath);
|
|
if (!fn.HasExt())
|
|
{
|
|
if (!(m_dialogStyle & FD_NO_ADD_EXTENSION))
|
|
{
|
|
wxStringTokenizer tokenizer( myData.extensions[m_filterIndex], wxT(";"));
|
|
if (tokenizer.HasMoreTokens())
|
|
{
|
|
wxString extension = tokenizer.GetNextToken().AfterFirst(wxT('.'));
|
|
if (extension.Right(2) == wxT("*"))
|
|
{
|
|
extension = wxEmptyString;
|
|
}
|
|
fn.SetExt(extension);
|
|
}
|
|
}
|
|
}
|
|
m_path = fn.GetFullPath();
|
|
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);
|
|
|
|
return (err == noErr) ? wxID_OK : wxID_CANCEL;
|
|
}
|
|
|
|
wxString FileDialog::ConvertSlashInFileName(const wxString& filePath)
|
|
{
|
|
#if TARGET_API_MAC_OSX
|
|
wxString path = filePath;
|
|
wxString filename;
|
|
wxString newPath = filePath;
|
|
int pathLen = 1;
|
|
while (!wxDirExists(wxPathOnly(newPath)) && ! path.IsEmpty())
|
|
{
|
|
path = newPath.BeforeLast('/');
|
|
filename = newPath.AfterLast('/');
|
|
newPath = path;
|
|
newPath += ':';
|
|
newPath += filename;
|
|
}
|
|
return newPath;
|
|
#else
|
|
return filePath;
|
|
#endif
|
|
}
|