]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/dirdlg.cpp
make sure we always restore the passed in cg in a paint event
[wxWidgets.git] / src / mac / carbon / dirdlg.cpp
index edfc211caa05465c25cd36acde69e55c778c1d88..49ae77655e9c4356930757b1925a31db8d61628c 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
-// Name:        dirdlg.cpp
+// Name:        src/mac/carbon/dirdlg.cpp
 // Purpose:     wxDirDialog
-// Author:      AUTHOR
+// Author:      Stefan Csomor
 // Modified by:
-// Created:     ??/??/98
+// Created:     1998-01-01
 // RCS-ID:      $Id$
-// Copyright:   (c) AUTHOR
-// Licence:    wxWindows licence
+// Copyright:   (c) Stefan Csomor
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-#pragma implementation "dirdlg.h"
-#endif
-
-#include "wx/defs.h"
-#include "wx/utils.h"
-#include "wx/dialog.h"
-#include "wx/dirdlg.h"
-
-#include "wx/cmndata.h"
-
-#if !USE_SHARED_LIBRARY
-IMPLEMENT_CLASS(wxDirDialog, wxDialog)
-#endif
-
-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
-};
-
-// 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 UserDataRec {
-       StandardFileReply       *sfrPtr;
-       FSSpec                          oldSelectionFSSpec;
-       DialogPtr                       theDlgPtr;
-};
-typedef struct UserDataRec
-       UserDataRec, *UserDataRecPtr;
-
-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);
+#include "wx/wxprec.h"
 
-       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);
+#if wxUSE_DIRDLG
 
-Bail:
-       if (nameHandle)         DisposeHandle(nameHandle);
-       if (labelHandle)        DisposeHandle(labelHandle);
-       
-}
+#include "wx/dirdlg.h"
 
-// FlashButton briefly highlights the dialog button 
-// as feedback for key equivalents
+#ifndef WX_PRECOMP
+    #include "wx/utils.h"
+    #include "wx/dialog.h"
+    #include "wx/cmndata.h"
+#endif // WX_PRECOMP
 
-static void FlashButton(DialogPtr theDlgPtr, short buttonID)
-{
-       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);
-}
+#include "wx/filename.h"
 
-static Boolean SameFSSpec(FSSpecPtr spec1, FSSpecPtr spec2)
-{
-       return (spec1->vRefNum == spec2->vRefNum
-                       && spec1->parID == spec2->parID
-                       && EqualString(spec1->name, spec2->name, false, false));
-}
-// 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)
-{
-#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
-               
-               if ((eventRec->what == keyDown)
-                       && (eventRec->modifiers & cmdKey) 
-                       && ((eventRec->message & charCodeMask) == GetSelectKey()))
-               {
-                       *item = kSelectItem;
-                       FlashButton(theDlgPtr, kSelectItem);
-                       return true;
-               }
-       }
-               
-       return false;
-}
+#include "wx/mac/private.h"
 
+#ifdef __DARWIN__
+    #include <Carbon/Carbon.h>
+#else
+    #include <Navigation.h>
+#endif
 
-// MyDlgHook is a hook routine that maps the select button to Open
-// and sets the Select button name
+IMPLEMENT_CLASS(wxDirDialog, wxDialog)
 
-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;
-       }
-       
-       // 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;
-}
+static pascal void NavEventProc(
+                                NavEventCallbackMessage inSelector,
+                                NavCBRecPtr ioParams,
+                                NavCallBackUserData ioUserData );
 
-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
-       
-       CopyPStr("\p ", theSFR->sfFile.name);
-       
-       // point the user data parameter at the reply record so we can get to it later
-       
-       myData.sfrPtr = theSFR;
-       
-       // display the dialog
-       
-       dlgHookUPP = NewDlgHookYDProc(SFGetFolderDialogHook);
-       myModalFilterUPP = NewModalFilterYDProc(SFGetFolderModalDialogFilter);
-       
-       thePt.h = thePt.v = -1; // center dialog
-       
-       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);
-       
-       // 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;
-                       }
-               }
-               
-               // 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 NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc);
 
-static pascal Boolean OnlyVisibleFoldersCustomFileFilter(CInfoPBPtr myCInfoPBPtr, Ptr dataPtr)
+static pascal void NavEventProc(
+                                NavEventCallbackMessage inSelector,
+                                NavCBRecPtr ioParams,
+                                NavCallBackUserData ioUserData )
 {
-#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);
+    wxDirDialog * data = ( wxDirDialog *) ioUserData ;
+    if ( inSelector == kNavCBStart )
+    {
+        if (data && !data->GetPath().empty() )
+        {
+            // Set default location for the modern Navigation APIs
+            // Apple Technical Q&A 1151
+            FSRef theFile;
+            wxMacPathToFSRef(data->GetPath(), &theFile);
+            AEDesc theLocation = { typeNull, NULL };
+            if (noErr == ::AECreateDesc(typeFSRef, &theFile, sizeof(FSRef), &theLocation))
+                 ::NavCustomControl(ioParams->context, kNavCtlSetLocation, (void *) &theLocation);
+        }
+    }
 }
 
-wxDirDialog::wxDirDialog(wxWindow *parent, const wxString& message,
-        const wxString& defaultPath,
-        long style, const wxPoint& pos)
+wxDirDialog::wxDirDialog(wxWindow *parent,
+                         const wxString& message,
+                         const wxString& defaultPath,
+                         long style,
+                         const wxPoint& WXUNUSED(pos),
+                         const wxSize& WXUNUSED(size),
+                         const wxString& WXUNUSED(name))
 {
+    wxASSERT_MSG( NavServicesAvailable() , wxT("Navigation Services are not running") ) ;
     m_message = message;
-    m_dialogStyle = style;
     m_parent = parent;
-       m_path = defaultPath;
+    m_path = defaultPath;
 }
 
 int wxDirDialog::ShowModal()
 {
-       {
-               Str255                          prompt ;
-               Str255                          path ;
-
-               strcpy((char *)prompt, m_message) ;
-               c2pstr((char *)prompt ) ;
-       
-               strcpy((char *)path, m_path ) ;
-               c2pstr((char *)path ) ;
-
-               FileFilterYDUPP         invisiblesExcludedCustomFilterUPP;
-               StandardFileReply       reply ;
-               invisiblesExcludedCustomFilterUPP = 
-                       NewFileFilterYDProc(OnlyVisibleFoldersCustomFileFilter);
-
-               StandardGetFolder( prompt , path , invisiblesExcludedCustomFilterUPP, &reply);
-       
-               DisposeRoutineDescriptor(invisiblesExcludedCustomFilterUPP);
-               if ( reply.sfGood == false )
-               {
-                       m_path = "" ;
-                       return wxID_CANCEL ;
-               }
-               else
-               {
-                       m_path = wxMacFSSpec2UnixFilename( &reply.sfFile ) ;
-                       return wxID_OK ;
-               }
-       }
-       return wxID_CANCEL;
+    NavDialogRef dialog;
+    NavDialogCreationOptions options;
+    NavReplyRecord reply ;
+    bool disposeReply = false ;
+    OSStatus err = noErr;
+
+    err = NavGetDefaultDialogCreationOptions(&options);
+    if (err == noErr)
+    {
+        wxMacCFStringHolder message(m_message, m_font.GetEncoding());
+        options.message = message;
+        err = NavCreateChooseFolderDialog(&options, sStandardNavEventFilter , NULL,  this , &dialog);
+        if (err == noErr)
+        {
+            err = NavDialogRun(dialog);
+            if ( err == noErr )
+            {
+                err = NavDialogGetReply(dialog, &reply);
+                disposeReply = true ;
+            }
+        }
+    }
+
+    if ( err == noErr )
+    {
+        if ( reply.validRecord )
+        {
+            FSRef folderInfo;
+            AEDesc specDesc ;
+
+            OSErr err = ::AECoerceDesc( &reply.selection , typeFSRef, &specDesc);
+            if ( err != noErr )
+            {
+                m_path = wxEmptyString ;
+            }
+            else
+            {
+                folderInfo = **(FSRef**) specDesc.dataHandle;
+                m_path = wxMacFSRefToPath( &folderInfo ) ;
+                if (specDesc.dataHandle != nil)
+                {
+                    ::AEDisposeDesc(&specDesc);
+                }
+            }
+        }
+        else
+        {
+            err = paramErr ; // could be any error, only used for giving back wxID_CANCEL
+        }
+    }
+
+    if ( disposeReply )
+        ::NavDisposeReply(&reply);
+
+    // apparently cancelling shouldn't change m_path
+    if ( err != noErr && err != userCanceledErr )
+        m_path = wxEmptyString ;
+
+    return (err == noErr) ? wxID_OK : wxID_CANCEL ;
 }
 
+#endif