home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / MacGzip 1.1.1 / Mac / GetFolder.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-01  |  8.3 KB  |  361 lines  |  [TEXT/KAHL]

  1. /*    StandardGetFolder example
  2.  
  3.     Steve Falkenburg -- MacDTS
  4.     
  5.     This sample uses the new System 7 CustomGetFile routine
  6.     to provide a StandardGetFolder call to be used by applications
  7.     when the user needs to select a folder instead of a file.
  8.     
  9.     It's written in Think C, but should work in MPW if a few #include
  10.     files are added.
  11.     
  12.     The style of the dialog box is taken from the Human Interface note
  13.     on folder selection.
  14.     
  15.     SJF        5/2/92        added check for empty filename and call to MakeFSSpec
  16.     SJF        5/2/92        added check for refcon in filter and hook routines
  17.     SJF        10/30/91    original coding
  18.     SPD        8/14/95        UPP and minor changes
  19.     
  20. */
  21.  
  22. #include <Folders.h>
  23. #include <Aliases.h>
  24.  
  25. #include "GzPStrings.h"
  26.  
  27. #if GENERATINGCFM || USESROUTINEDESCRIPTORS
  28. #  define CreateRoutineDescriptor(info, proc)                                    \
  29.         RoutineDescriptor g##proc##RD = BUILD_ROUTINE_DESCRIPTOR(info, proc)
  30. #  define GetRoutineAddress(proc)    (&g##proc##RD)
  31. #else
  32. #  define GetRoutineAddress(proc)    proc
  33. #endif
  34.  
  35. /* prototypes */
  36.  
  37. Boolean SFGetFolder(FSSpec *fSpec);
  38.  
  39. static void InitStuff(void);
  40. static pascal short MyDlgHook(short item,DialogPtr theDlg,Ptr userData);
  41. static pascal Boolean MyModalFilter(DialogPtr theDlg,EventRecord *ev,short *itemHit,Ptr myData);
  42. static void HitButton(DialogPtr theDlg,short item);
  43. static pascal Boolean FilterAllFiles(CInfoPBPtr pb, Ptr myDataPtr);
  44. static void SetSelectButtonName(StringPtr selName,Boolean hilited,DialogPtr theDlg);
  45. static Boolean SameFile(FSSpec *file1,FSSpec *file2);
  46. static Boolean GetFSSpecPartialName(FSSpec *file,StringPtr fName);
  47. static OSErr GetDeskFolderSpec(FSSpec *fSpec,short vRefNum);
  48. static OSErr MakeCanonFSSpec(FSSpec *fSpec);
  49. static Boolean ShouldHiliteSelect(FSSpec *fSpec);
  50.  
  51. /* typedefs */
  52.  
  53. typedef struct {
  54.     StandardFileReply *replyPtr;
  55.     FSSpec oldSelection;
  56. } SFData, *SFDataPtr;
  57.  
  58. /* constants */
  59.  
  60. #define    kSelectItem            10
  61. #define    kSFDlg                129
  62. #define    kCanSelectDesktop    true
  63. #define    kSelectStrRsrc        128
  64. #define kDefaultSelectString "\pSelect"
  65. #define    kDeskStrRsrc        129
  66. #define    kDefaultDeskString    "\pDesktop"
  67. #define    kSelectKey            's'
  68.  
  69. /* globals */
  70.  
  71. FSSpec gDeskFolderSpec;
  72. Str255 gSelectString;
  73. Str255 gDesktopFName;
  74.  
  75. /*
  76.  * Usage:
  77.  *    FSSpec fSpec;
  78.  *    Boolean good;
  79.  *
  80.  *  extern Boolean SFGetFolder(FSSpec *fSpec);
  81.  *    good = SFGetFolder(&fSpec);
  82.  */
  83.  
  84.  
  85. /* initialize managers */
  86.  
  87. static void InitStuff(void)
  88. {
  89.     Handle strHndl;
  90.         
  91.     strHndl = Get1Resource('STR ',kSelectStrRsrc);
  92.     if (ResError()!=noErr || !strHndl || !*strHndl)
  93.         BlockMove(kDefaultSelectString,gSelectString,kDefaultSelectString[0]+1);
  94.     else
  95.     {
  96.         BlockMove(*strHndl,&gSelectString,(long)((unsigned char *)(*strHndl)[0]+1));
  97.         ReleaseResource(strHndl);
  98.     }
  99.  
  100.     strHndl = Get1Resource('STR ',kDeskStrRsrc);
  101.     if (ResError()!=noErr || !strHndl || !*strHndl)
  102.         BlockMove(kDefaultDeskString,gDesktopFName,kDefaultSelectString[0]+1);
  103.     else
  104.     {
  105.         BlockMove(*strHndl,&gDesktopFName,(long)((unsigned char *)(*strHndl)[0]+1));
  106.         ReleaseResource(strHndl);
  107.     }
  108. }
  109.  
  110.  
  111. /* do getfile */
  112.  
  113. Boolean SFGetFolder(FSSpec *fSpec)
  114. {
  115.     Point                where = {-1,-1};
  116.     StandardFileReply    sfReply;
  117.     SFData                sfUserData;
  118.     OSErr                err;
  119.     Boolean                targetIsFolder,
  120.                         wasAliased;
  121.     
  122. #if GENERATINGCFM || USESROUTINEDESCRIPTORS
  123.     CreateRoutineDescriptor(uppFileFilterYDProcInfo, FilterAllFiles);
  124.     CreateRoutineDescriptor(uppDlgHookYDProcInfo, MyDlgHook);
  125.     CreateRoutineDescriptor(uppModalFilterYDProcInfo, MyModalFilter);
  126. #endif
  127.     
  128.     InitStuff();
  129.  
  130. /* initialize user data area */
  131.     
  132.     sfUserData.replyPtr = &sfReply;
  133.     sfUserData.oldSelection.vRefNum = -9999;    /* init to ridiculous value */
  134.     
  135.     CustomGetFile(
  136.                     (FileFilterYDUPP)GetRoutineAddress(FilterAllFiles),
  137.                     -1,nil,
  138.                     &sfReply,
  139.                     kSFDlg,
  140.                     where,
  141.                     (DlgHookYDUPP)GetRoutineAddress(MyDlgHook),
  142.                     (ModalFilterYDUPP)GetRoutineAddress(MyModalFilter),
  143.                     nil,nil,&sfUserData);
  144.     
  145.     
  146.     if (sfReply.sfGood)
  147.     {
  148.         MakeCanonFSSpec(&sfReply.sfFile); /* spd, August 29, 1995 */
  149.         
  150.         err = ResolveAliasFile(&sfReply.sfFile,true,&targetIsFolder,&wasAliased);
  151.         if (err!=noErr)
  152.             return false;
  153.     }
  154.     
  155.     err = FSMakeFSSpec(sfReply.sfFile.vRefNum,sfReply.sfFile.parID,sfReply.sfFile.name,fSpec);
  156.     if (err!=noErr)
  157.         return false;
  158.     
  159.     return sfReply.sfGood;
  160. }
  161.  
  162.  
  163. /*    this dialog hook checks the contents of the additional edit fields
  164.     when the user selects a file.  The focus of the dialog is changed if one
  165.     of the fields is out of range.
  166. */
  167.  
  168. static pascal short MyDlgHook(short item,DialogPtr theDlg,Ptr userData)
  169. {
  170.     SFDataPtr sfUserData;
  171.     FSSpec curSpec;
  172.     OSType refCon;
  173.     
  174.     refCon = GetWRefCon(theDlg);
  175.     if (refCon!=sfMainDialogRefCon)
  176.         return item;
  177.         
  178.     sfUserData = (SFDataPtr) userData;
  179.     
  180.     if (item==sfHookFirstCall || item==sfHookLastCall)
  181.         return item;
  182.     
  183.     if (item==sfItemVolumeUser) {
  184.         sfUserData->replyPtr->sfFile.name[0] = '\0';
  185.         sfUserData->replyPtr->sfFile.parID = 2;
  186.         sfUserData->replyPtr->sfIsFolder = false;
  187.         sfUserData->replyPtr->sfIsVolume = false;
  188.         sfUserData->replyPtr->sfFlags = 0;
  189.         item = sfHookChangeSelection;
  190.     }
  191.         
  192.     if (!SameFile(&sfUserData->replyPtr->sfFile,&sfUserData->oldSelection)) {
  193.         BlockMove(&sfUserData->replyPtr->sfFile,&curSpec,sizeof(FSSpec));
  194.         MakeCanonFSSpec(&curSpec);
  195.         
  196.         if (curSpec.vRefNum!=sfUserData->oldSelection.vRefNum)
  197.             GetDeskFolderSpec(&gDeskFolderSpec,curSpec.vRefNum);    
  198.         SetSelectButtonName(curSpec.name,ShouldHiliteSelect(&curSpec),theDlg);
  199.         
  200.         BlockMove(&sfUserData->replyPtr->sfFile,&sfUserData->oldSelection,sizeof(FSSpec));
  201.     }
  202.     
  203.     if (item==kSelectItem)
  204.         item = sfItemOpenButton;
  205.         
  206.     return item;
  207. }
  208.  
  209.  
  210. static pascal Boolean MyModalFilter(DialogPtr theDlg,EventRecord *ev,short *itemHit,Ptr myData)
  211. {
  212.     Boolean evHandled;
  213.     char keyPressed;
  214.     OSType refCon;
  215.     
  216.     refCon = GetWRefCon(theDlg);
  217.     if (refCon!=sfMainDialogRefCon)
  218.         return false;
  219.         
  220.     evHandled = false;
  221.     
  222.     switch (ev->what)
  223.     {
  224.         case keyDown:
  225.         case autoKey:
  226.             keyPressed = ev->message & charCodeMask;
  227.             if ((ev->modifiers & cmdKey) != 0)
  228.             {
  229.                 switch (keyPressed)
  230.                 {
  231.                     case kSelectKey:
  232.                         HitButton(theDlg,kSelectItem);
  233.                         *itemHit = kSelectItem;
  234.                         evHandled = true;
  235.                         break;
  236.                 }
  237.             }
  238.             break;
  239.     }
  240.     
  241.     return evHandled;
  242. }
  243.  
  244.  
  245. static void HitButton(DialogPtr theDlg,short item)
  246. {
  247.     short iType;
  248.     ControlHandle iHndl;
  249.     Rect iRect;
  250.     long fTicks;
  251.     
  252.     GetDItem(theDlg,item,&iType,(Handle *)&iHndl,&iRect);
  253.     HiliteControl(iHndl,inButton);
  254.     Delay(5,&fTicks);
  255.     HiliteControl(iHndl,0);
  256. }
  257.  
  258.  
  259. static pascal Boolean FilterAllFiles(CInfoPBPtr pb, Ptr myDataPtr)
  260. {
  261.     if (pb->hFileInfo.ioFlAttrib & (1<<4))    /* file is a directory */
  262.         return false;
  263.  
  264.     return true;
  265. }
  266.  
  267.  
  268. static void SetSelectButtonName(StringPtr selName,Boolean hilited,DialogPtr theDlg)
  269. {
  270.     short iType;
  271.     Handle iHndl;
  272.     Rect iRect;
  273.     Str255 storeName,tempLenStr,tempSelName;
  274.     short btnWidth;
  275.     
  276.     BlockMove(selName,tempSelName,selName[0]+1);
  277.     GetDItem(theDlg,kSelectItem,&iType,&iHndl,&iRect);
  278.     
  279.     /* truncate select name to fit in button */
  280.     
  281.     btnWidth = iRect.right - iRect.left;
  282.     BlockMove(gSelectString,tempLenStr,gSelectString[0]+1);
  283.     PStrCat(tempLenStr, "\p ā€œā€  ");
  284.     btnWidth -= StringWidth(tempLenStr);
  285.     TruncString(btnWidth,tempSelName,smTruncMiddle);
  286.     
  287.     BlockMove(gSelectString,storeName,gSelectString[0]+1);
  288.  
  289.  
  290.     PStrCat( storeName, "\p ā€œ");
  291.     PStrCat( storeName, tempSelName);
  292.     PStrCat( storeName, "\pā€");
  293.  
  294.     SetCTitle((ControlHandle)iHndl,storeName);
  295.     
  296.     SetDItem(theDlg,kSelectItem,iType,iHndl,&iRect);
  297.  
  298.     if (hilited)
  299.         HiliteControl((ControlHandle)iHndl,0);
  300.     else
  301.         HiliteControl((ControlHandle)iHndl,255);        
  302. }
  303.  
  304.  
  305. static Boolean SameFile(FSSpec *file1,FSSpec *file2)
  306. {
  307.     if (file1->vRefNum != file2->vRefNum)
  308.         return false;
  309.     if (file1->parID != file2->parID)
  310.         return false;
  311.     if (!EqualString(file1->name,file2->name,false,true))
  312.         return false;
  313.     
  314.     return true;
  315. }
  316.  
  317.  
  318. static OSErr GetDeskFolderSpec(FSSpec *fSpec,short vRefNum)
  319. {
  320.     OSErr err;
  321.     
  322.     fSpec->name[0] = '\0';
  323.     err = FindFolder(vRefNum,kDesktopFolderType,kDontCreateFolder,
  324.                         &fSpec->vRefNum,&fSpec->parID);
  325.     if (err!=noErr)
  326.         return err;
  327.     
  328.     return MakeCanonFSSpec(fSpec);
  329. }
  330.  
  331.  
  332. static Boolean ShouldHiliteSelect(FSSpec *fSpec)
  333. {
  334.     if (SameFile(fSpec,&gDeskFolderSpec)) {
  335.         BlockMove(gDesktopFName,fSpec->name,gDesktopFName[0]+1);
  336.         return kCanSelectDesktop;
  337.     }
  338.     else
  339.         return true;
  340. }
  341.  
  342.  
  343. static OSErr MakeCanonFSSpec(FSSpec *fSpec)
  344. {
  345.     DirInfo infoPB;
  346.     OSErr err;
  347.  
  348.     if (fSpec->name[0] != '\0')
  349.         return noErr;
  350.         
  351.     infoPB.ioNamePtr = fSpec->name;
  352.     infoPB.ioVRefNum = fSpec->vRefNum;
  353.     infoPB.ioDrDirID = fSpec->parID;
  354.     infoPB.ioFDirIndex = -1;
  355.     err = PBGetCatInfo((CInfoPBPtr)&infoPB,false);
  356.     fSpec->parID = infoPB.ioDrParID;
  357.     
  358.     return err;
  359. }
  360.  
  361.