]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/dirdlg.cpp
survive delete within Notify
[wxWidgets.git] / src / mac / dirdlg.cpp
index e1255db7e1194af75eb32862a22db93565cbcd27..d38dc40a495a7baa614da489ed638f138884386e 100644 (file)
 
 #include "wx/cmndata.h"
 
-#if defined(__UNIX__)
-  #include <NavigationServices/Navigation.h>
+#include "wx/mac/private.h"
+
+#ifdef __DARWIN__
+  #include <Carbon/Carbon.h>
 #else
   #include <Navigation.h>
 #endif
 IMPLEMENT_CLASS(wxDirDialog, wxDialog)
 #endif
 
-bool gUseNavServices = NavServicesAvailable() ;
-
-// 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
-
-#if !TARGET_CARBON
-
-struct UserDataRec {
-       StandardFileReply       *sfrPtr;
-       FSSpec                          oldSelectionFSSpec;
-       DialogPtr                       theDlgPtr;
-};
-typedef struct UserDataRec
-       UserDataRec, *UserDataRecPtr;
-
-enum {
-       kSelectItem = 10,                       // select button item number
-       kSFGetFolderDlgID = 250,        // dialog resource number
-       kStrListID = 250,                       // our strings
-       kSelectStrNum = 1,                      // word 'Select: ' for button
-       kDesktopStrNum = 2,                     // word 'Desktop' for button
-       kSelectNoQuoteStrNum = 3,       // word 'Select: ' for button
-       
-       kUseQuotes = true,                      // parameter for SetButtonName
-       kDontUseQuotes = false
-};
-
-
-static void GetLabelString(StringPtr theStr, short stringNum)
-{
-       GetIndString(theStr, kStrListID, stringNum);
-}
-
-static void CopyPStr(StringPtr src, StringPtr dest)
-{
-       BlockMoveData(src, dest, 1 + src[0]);
-}
-
-static char GetSelectKey(void)
-{
-       // this is the key used to trigger the select button
-       
-       // NOT INTERNATIONAL SAVVY; should at least grab it from resources
-       
-       return 's';
-}
-
-
-// SetButtonName sets the name of the Select button in the dialog
-//
-// To do this, we need to call the Script Manager to truncate the
-// label in the middle to fit the button and to merge the button
-// name with the word Select (possibly followed by quotes).  Using
-// the Script Manager avoids all sorts of problems internationally.
-//
-// buttonName is the name to appear following the word Select
-// quoteFlag should be true if the name is to appear in quotes
-
-static void SetButtonName(DialogPtr theDlgPtr, short buttonID, StringPtr buttonName,
-                                       Boolean quoteFlag)
-{
-       short   buttonType;
-       Handle  buttonHandle;
-       Rect    buttonRect;
-       short   textWidth;
-       Handle  labelHandle;
-       Handle  nameHandle;
-       Str15   keyStr;
-       Str255  labelStr;
-       OSErr   err;
-       
-       nameHandle = nil;
-       labelHandle = nil;
-       
-       // get the details of the button from the dialog
-       
-       GetDialogItem(theDlgPtr, buttonID, &buttonType, &buttonHandle, &buttonRect);
-       
-       // get the string for the select button label, "Select ^0" or "Select Ò^0Ó"
-       
-       GetLabelString(labelStr, (quoteFlag == kUseQuotes) ? kSelectStrNum : kSelectNoQuoteStrNum);
-       
-       // make string handles containing the select button label and the
-       // file name to be stuffed into the button
-       
-       err = PtrToHand(&labelStr[1], &labelHandle, labelStr[0]);
-       if (err != noErr) goto Bail;
-       
-       // cut out the middle of the file name to fit the button
-       //
-       // we'll temporarily use labelStr here to hold the modified button name
-       // since we don't own the buttonName string storage space
-       
-       textWidth = (buttonRect.right - buttonRect.left) - StringWidth(labelStr);
-
-       CopyPStr(buttonName, labelStr);
-       (void) TruncString(textWidth, labelStr, smTruncMiddle);
-       
-       err = PtrToHand(&labelStr[1], &nameHandle, labelStr[0]);
-       if (err != noErr) goto Bail;
-       
-       // replace the ^0 in the Select string with the file name
-       
-       CopyPStr("\p^0", keyStr);
-       
-       (void) ReplaceText(labelHandle, nameHandle, keyStr);
-       
-       labelStr[0] = (unsigned char) GetHandleSize(labelHandle);
-       BlockMoveData(*labelHandle, &labelStr[1], labelStr[0]);
-       
-       // now set the control title, and re-validate the area
-       // above the control to avoid a needless redraw
-       
-       SetControlTitle((ControlHandle) buttonHandle, labelStr);
-       
-       ValidRect(&buttonRect);
-
-Bail:
-       if (nameHandle)         DisposeHandle(nameHandle);
-       if (labelHandle)        DisposeHandle(labelHandle);
-       
-}
-
-// FlashButton briefly highlights the dialog button 
-// as feedback for key equivalents
-
-static void FlashButton(DialogPtr theDlgPtr, short buttonID)
+wxDirDialog::wxDirDialog(wxWindow *parent,
+                         const wxString& message,
+                         const wxString& defaultPath,
+                         long style,
+                         const wxPoint& WXUNUSED(pos),
+                         const wxSize& WXUNUSED(size),
+                         const wxString& WXUNUSED(name))
 {
-       short   buttonType;
-       Handle  buttonHandle;
-       Rect    buttonRect;
-       unsigned long   finalTicks;
-       
-       GetDialogItem(theDlgPtr, buttonID, &buttonType, &buttonHandle, &buttonRect);
-       HiliteControl((ControlHandle) buttonHandle, kControlButtonPart);
-       Delay(10, &finalTicks);
-       HiliteControl((ControlHandle) buttonHandle, 0);
-}
-
-static Boolean SameFSSpec(FSSpecPtr spec1, FSSpecPtr spec2)
-{
-       return (spec1->vRefNum == spec2->vRefNum
-                       && spec1->parID == spec2->parID
-                       && EqualString(spec1->name, spec2->name, false, false));
+       wxASSERT_MSG( NavServicesAvailable() , "Navigation Services are not running" ) ;
+    m_message = message;
+    m_dialogStyle = style;
+    m_parent = parent;
+       m_path = defaultPath;
 }
-// MyModalDialogFilter maps a key to the Select button, and handles
-// flashing of the button when the key is hit
 
-static pascal Boolean SFGetFolderModalDialogFilter(DialogPtr theDlgPtr, EventRecord *eventRec,
-                                                                                       short *item, Ptr dataPtr)
+int wxDirDialog::ShowModal()
 {
-#pragma unused (dataPtr)
-
-       // make certain the proper dialog is showing, 'cause standard file
-       // can nest dialogs but calls the same filter for each
-       
-       if (((WindowPeek) theDlgPtr)->refCon == sfMainDialogRefCon)
-       {
-               // check if the select button was hit
+       NavDialogOptions                mNavOptions;
+       NavObjectFilterUPP              mNavFilterUPP = NULL;
+       NavPreviewUPP                   mNavPreviewUPP = NULL ;
+       NavReplyRecord                  mNavReply;
+       AEDesc*                                 mDefaultLocation = NULL ;
+       bool                                    mSelectDefault = false ;
+       
+       ::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
+       
+       if ( mDefaultLocation ) {
                
-               if ((eventRec->what == keyDown)
-                       && (eventRec->modifiers & cmdKey) 
-                       && ((eventRec->message & charCodeMask) == GetSelectKey()))
-               {
-                       *item = kSelectItem;
-                       FlashButton(theDlgPtr, kSelectItem);
-                       return true;
+               if (mSelectDefault) {
+                       mNavOptions.dialogOptionFlags |= kNavSelectDefaultLocation;
+               } else {
+                       mNavOptions.dialogOptionFlags &= ~kNavSelectDefaultLocation;
                }
        }
-               
-       return false;
-}
-
-
-// MyDlgHook is a hook routine that maps the select button to Open
-// and sets the Select button name
-
-static pascal short SFGetFolderDialogHook(short item, DialogPtr theDlgPtr, Ptr dataPtr)
-{
-       UserDataRecPtr  theUserDataRecPtr;
-       long                    desktopDirID;
-       short                   desktopVRefNum;
-       FSSpec                  tempSpec;
-       Str63                   desktopName;
-       OSErr                   err;
-       
-       // be sure Std File is really showing us the intended dialog,
-       // not a nested modal dialog
-       
-       if (((WindowPeek) theDlgPtr)->refCon != sfMainDialogRefCon)
-       {
-               return item;
-       }
-       
-       theUserDataRecPtr = (UserDataRecPtr) dataPtr;
-       
-       // map the Select button to Open
        
-       if (item == kSelectItem)
-       {
-               item = sfItemOpenButton;
+       OSErr err = ::NavChooseFolder(
+                                               mDefaultLocation,
+                                               &mNavReply,
+                                               &mNavOptions,
+                                               NULL,
+                                               mNavFilterUPP,
+                                               0L);                                                    // User Data
+       
+       if ( (err != noErr) && (err != userCanceledErr) ) {
+               m_path = "" ;
+               return wxID_CANCEL ;
        }
-       
-       // find the desktop folder
-       
-       err = FindFolder(theUserDataRecPtr->sfrPtr->sfFile.vRefNum,
-                                       kDesktopFolderType, kDontCreateFolder,
-                                       &desktopVRefNum, &desktopDirID);
-       
-       if (err != noErr)
-       {
-               // for errors, get value that won't match any real vRefNum/dirID
-               desktopVRefNum = 0;
-               desktopDirID = 0;
-       }
-       
-       // change the Select button label if the selection has changed or
-       // if this is the first call to the hook
-       
-       if (item == sfHookFirstCall
-               || item == sfHookChangeSelection
-               || item == sfHookRebuildList
-               || ! SameFSSpec(&theUserDataRecPtr->sfrPtr->sfFile,
-                                       &theUserDataRecPtr->oldSelectionFSSpec))
-       {
-               // be sure there is a file name selected
-               
-               if (theUserDataRecPtr->sfrPtr->sfFile.name[0] != '\0')
-               {
-                       SetButtonName(theDlgPtr, kSelectItem, 
-                                                       theUserDataRecPtr->sfrPtr->sfFile.name, 
-                                                       kUseQuotes);    // true -> use quotes
-               }
-               else
-               {
-                       // is the desktop selected?
-                       
-                       if (theUserDataRecPtr->sfrPtr->sfFile.vRefNum == desktopVRefNum
-                               && theUserDataRecPtr->sfrPtr->sfFile.parID == desktopDirID)
-                       {
-                               // set button to "Select Desktop"
-                               
-                               GetLabelString(desktopName, kDesktopStrNum);
-                               SetButtonName(theDlgPtr, kSelectItem, 
-                                                               desktopName, kDontUseQuotes);   // false -> no quotes
-                       }
-                       else
-                       {
-                               // get parent directory's name for the Select button
-                               //
-                               // passing an empty name string to FSMakeFSSpec gets the
-                               // name of the folder specified by the parID parameter
-                               
-                               (void) FSMakeFSSpec(theUserDataRecPtr->sfrPtr->sfFile.vRefNum,
-                                       theUserDataRecPtr->sfrPtr->sfFile.parID, "\p",
-                                       &tempSpec);
-                               SetButtonName(theDlgPtr, kSelectItem, 
-                                                       tempSpec.name, kUseQuotes); // true -> use quotes
-                       }
-               }
-       }
-       
-       // save the current selection as the old selection for comparison next time
-       //
-       // it's not valid on the first call, though, or if we don't have a 
-       // name available from standard file
-       
-       if (item != sfHookFirstCall || theUserDataRecPtr->sfrPtr->sfFile.name[0] != '\0')
-       {
-               theUserDataRecPtr->oldSelectionFSSpec = theUserDataRecPtr->sfrPtr->sfFile;
-       }
-       else
-       {
-               // on first call, empty string won't set the button correctly, 
-               // so invalidate oldSelection
-               
-               theUserDataRecPtr->oldSelectionFSSpec.vRefNum = 999;
-               theUserDataRecPtr->oldSelectionFSSpec.parID = 0;
-       }
-       
-       return item;
-}
 
-void StandardGetFolder( ConstStr255Param message , ConstStr255Param path , FileFilterYDUPP fileFilter, StandardFileReply *theSFR)
-{
-       Point                           thePt;
-       SFTypeList                      mySFTypeList;
-       UserDataRec                     myData;
-       FSSpec                          tempSpec;
-       Boolean                         folderFlag;
-       Boolean                         wasAliasedFlag;
-       DlgHookYDUPP            dlgHookUPP;
-       ModalFilterYDUPP        myModalFilterUPP;
-       OSErr                           err;
-       
-       
-       // presumably we're running System 7 or later so CustomGetFile is
-       // available
-       
-       // set initial contents of Select button to a space
-       
-       memcpy(theSFR->sfFile.name, "\p ", 2);
-       
-       // point the user data parameter at the reply record so we can get to it later
-       
-       myData.sfrPtr = theSFR;
-       
-       // display the dialog
-       
-       #if !TARGET_CARBON
-       
-       dlgHookUPP = NewDlgHookYDProc(SFGetFolderDialogHook);
-       myModalFilterUPP = NewModalFilterYDProc(SFGetFolderModalDialogFilter);
-       
-       thePt.h = thePt.v = -1; // center dialog
+       if (mNavReply.validRecord) {            // User chose a folder
        
-       ParamText( message , NULL , NULL , NULL ) ;
-       
-       CustomGetFile(  fileFilter, 
-                                       -1,                                     // show all types
-                                       mySFTypeList,
-                                       theSFR,
-                                       kSFGetFolderDlgID,
-                                       thePt,                          // top left point
-                                       dlgHookUPP,
-                                       myModalFilterUPP,
-                                       nil,                            // activate list
-                                       nil,                            // activate proc
-                                       &myData);
-                                       
-       DisposeRoutineDescriptor(dlgHookUPP);
-       DisposeRoutineDescriptor(myModalFilterUPP);
-       #else
-       #endif
-       
-       // if cancel wasn't pressed and no fatal error occurred...
-       
-       if (theSFR->sfGood)
-       {
-               // if no name is in the reply record file spec,
-               // use the file spec of the parent folder
-               
-               if (theSFR->sfFile.name[0] == '\0')
-               {
-                       err = FSMakeFSSpec(theSFR->sfFile.vRefNum, theSFR->sfFile.parID,
-                                                               "\p", &tempSpec);
-                       if (err == noErr)
-                       {
-                               theSFR->sfFile = tempSpec;
-                       }
-                       else
-                       {
-                               // no name to return, forget it
-                               
-                               theSFR->sfGood = false;
-                       }
-               }
+               FSSpec  folderInfo;
+               FSSpec  outFileSpec ;
+               AEDesc specDesc ;
                
-               // if there is now a name in the file spec, check if it's
-               // for a folder or a volume
-               
-               if (theSFR->sfFile.name[0] != '\0')
-               {
-                       // the parID of the root of a disk is always fsRtParID == 1
-                       
-                       if (theSFR->sfFile.parID == fsRtParID)
-                       {
-                               theSFR->sfIsVolume = true;
-                               theSFR->sfIsFolder = false;     // it would be reasonable for this to be true, too
-                       }
-                       
-                       // we have a valid FSSpec, now let's make sure it's not for an alias file
-                       
-                       err = ResolveAliasFile(&theSFR->sfFile, true, &folderFlag, &wasAliasedFlag);
-                       if (err != noErr)
-                       {
-                               theSFR->sfGood = false;
-                       }
-                       
-                       // did the alias resolve to a folder?
-                       
-                       if (folderFlag  && ! theSFR->sfIsVolume)
-                       {
-                               theSFR->sfIsFolder = true;
-                       }
-               }
-       }
-}
-
-static pascal Boolean OnlyVisibleFoldersCustomFileFilter(CInfoPBPtr myCInfoPBPtr, Ptr dataPtr)
-{
-#pragma unused (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
-       
-       return !(visibleFlag && folderFlag);
-}
-
-#endif
-
-
-wxDirDialog::wxDirDialog(wxWindow *parent, const wxString& message,
-        const wxString& defaultPath,
-        long style, const wxPoint& pos)
-{
-    m_message = message;
-    m_dialogStyle = style;
-    m_parent = parent;
-       m_path = defaultPath;
-}
-
-int wxDirDialog::ShowModal()
-{
-       #if !TARGET_CARBON
-       if ( !gUseNavServices )
-       {
-               Str255                          prompt ;
-               Str255                          path ;
-
-#if TARGET_CARBON
-               c2pstrcpy((StringPtr)prompt, m_message) ;
-#else
-               strcpy((char *)prompt, m_message) ;
-               c2pstr((char *)prompt ) ;
-#endif
-#if TARGET_CARBON
-               c2pstrcpy((StringPtr)path, m_path ) ;
-#else
-               strcpy((char *)path, m_path ) ;
-               c2pstr((char *)path ) ;
-#endif
-
-               StandardFileReply       reply ;
-               FileFilterYDUPP         invisiblesExcludedCustomFilterUPP = 0 ;
-               invisiblesExcludedCustomFilterUPP = 
-                       NewFileFilterYDProc(OnlyVisibleFoldersCustomFileFilter);
-
-
-               StandardGetFolder( prompt , path , invisiblesExcludedCustomFilterUPP, &reply);
-       
-
-               DisposeRoutineDescriptor(invisiblesExcludedCustomFilterUPP);
-
-               if ( reply.sfGood == false )
-               {
+               OSErr err = ::AECoerceDesc( &mNavReply.selection , typeFSS, &specDesc);
+               if ( err != noErr ) {
                        m_path = "" ;
                        return wxID_CANCEL ;
+               }                       
+               folderInfo = **(FSSpec**) specDesc.dataHandle;
+               if (specDesc.dataHandle != nil) {
+                       ::AEDisposeDesc(&specDesc);
                }
-               else
-               {
-                       m_path = wxMacFSSpec2UnixFilename( &reply.sfFile ) ;
-                       return wxID_OK ;
-               }
-               return wxID_CANCEL;
-       }
-       else
-       #endif
-       {
-               NavDialogOptions                mNavOptions;
-               NavObjectFilterUPP              mNavFilterUPP = NULL;
-               NavPreviewUPP                   mNavPreviewUPP = NULL ;
-               NavReplyRecord                  mNavReply;
-               AEDesc*                                 mDefaultLocation = NULL ;
-               bool                                    mSelectDefault = false ;
-               
-               ::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
+
+//                     mNavReply.GetFileSpec(folderInfo);
                
-               if ( mDefaultLocation ) {
-                       
-                       if (mSelectDefault) {
-                               mNavOptions.dialogOptionFlags |= kNavSelectDefaultLocation;
-                       } else {
-                               mNavOptions.dialogOptionFlags &= ~kNavSelectDefaultLocation;
-                       }
-               }
+                       // The FSSpec from NavChooseFolder is NOT the file spec
+                       // for the folder. The parID field is actually the DirID
+                       // of the folder itself, not the folder's parent, and
+                       // the name field is empty. We must call PBGetCatInfo
+                       // to get the parent DirID and folder name
                
-               OSErr err = ::NavChooseFolder(
-                                                       mDefaultLocation,
-                                                       &mNavReply,
-                                                       &mNavOptions,
-                                                       NULL,
-                                                       mNavFilterUPP,
-                                                       0L);                                                    // User Data
+               Str255          name;
+               CInfoPBRec      thePB;                  // Directory Info Parameter Block
+               thePB.dirInfo.ioCompletion      = nil;
+               thePB.dirInfo.ioVRefNum         = folderInfo.vRefNum;   // Volume is right
+               thePB.dirInfo.ioDrDirID         = folderInfo.parID;             // Folder's DirID
+               thePB.dirInfo.ioNamePtr         = name;
+               thePB.dirInfo.ioFDirIndex       = -1;   // Lookup using Volume and DirID
                
-               if ( (err != noErr) && (err != userCanceledErr) ) {
+               err = ::PBGetCatInfoSync(&thePB);
+               if ( err != noErr ) {
                        m_path = "" ;
                        return wxID_CANCEL ;
-               }
-
-               if (mNavReply.validRecord) {            // User chose a folder
-               
-                       FSSpec  folderInfo;
-                       FSSpec  outFileSpec ;
-                       AEDesc specDesc ;
-                       
-                       OSErr err = ::AECoerceDesc( &mNavReply.selection , typeFSS, &specDesc);
-                       if ( err != noErr ) {
-                               m_path = "" ;
-                               return wxID_CANCEL ;
-                       }                       
-                       folderInfo = **(FSSpec**) specDesc.dataHandle;
-                       if (specDesc.dataHandle != nil) {
-                               ::AEDisposeDesc(&specDesc);
-                       }
-
-//                     mNavReply.GetFileSpec(folderInfo);
-                       
-                               // The FSSpec from NavChooseFolder is NOT the file spec
-                               // for the folder. The parID field is actually the DirID
-                               // of the folder itself, not the folder's parent, and
-                               // the name field is empty. We must call PBGetCatInfo
-                               // to get the parent DirID and folder name
-                       
-                       Str255          name;
-                       CInfoPBRec      thePB;                  // Directory Info Parameter Block
-                       thePB.dirInfo.ioCompletion      = nil;
-                       thePB.dirInfo.ioVRefNum         = folderInfo.vRefNum;   // Volume is right
-                       thePB.dirInfo.ioDrDirID         = folderInfo.parID;             // Folder's DirID
-                       thePB.dirInfo.ioNamePtr         = name;
-                       thePB.dirInfo.ioFDirIndex       = -1;   // Lookup using Volume and DirID
-                       
-                       err = ::PBGetCatInfoSync(&thePB);
-                       if ( err != noErr ) {
-                               m_path = "" ;
-                               return wxID_CANCEL ;
-                       }                       
-                                                                                               // Create cannonical FSSpec
-                       ::FSMakeFSSpec(thePB.dirInfo.ioVRefNum, thePB.dirInfo.ioDrParID,
-                                                  name, &outFileSpec);
-                                                       
-                       // outFolderDirID = thePB.dirInfo.ioDrDirID;
-                       m_path = wxMacFSSpec2UnixFilename( &outFileSpec ) ;
-                       return wxID_OK ;
-               }
-               return wxID_CANCEL;
-
+               }                       
+                                                                                       // Create cannonical FSSpec
+               ::FSMakeFSSpec(thePB.dirInfo.ioVRefNum, thePB.dirInfo.ioDrParID,
+                                          name, &outFileSpec);
+                                               
+               // outFolderDirID = thePB.dirInfo.ioDrDirID;
+               m_path = wxMacFSSpec2MacFilename( &outFileSpec ) ;
+               return wxID_OK ;
        }
+       return wxID_CANCEL;
 }