/* File: alDialog.c Contains: Implementation of SelectAlias dialog box. Written by: Prashant Patel Copyright: © 1989-1990 by Apple Computer, Inc., all rights reserved. Change History (most recent first): <13> 10/21/90 gbm Changing hfileInfo to hFileInfo. <13> 10/15/90 JL Changing hfileInfo to hFileInfo it should have never been changed back. <12> 6/8/90 ngk update for changes to StandardFile.h <11> 5/16/90 PP Parameters to AL_findVolume has cahnged. <10> 5/3/90 PP Incorporate Diet tips. <9> 4/10/90 PP Change once more hFileInfo to hfileInfo to stay consistent with Files.h <8> 4/5/90 PP Change "callbackPtr" to "yourDataPtr". <7> 3/8/90 JAL Changed hfileInfo to hFileInfo to stay consistent with change in Files.h <6> 3/5/90 PKE Added smTruncEnd as truncWhere parameter for TruncString call, since TruncString interface now matches former NTruncString interface. <5> 2/26/90 ngk Changed names of new standardfile calls to match header. <4> 2/26/90 dnf Change capitalization to match changes in files.h, rename positionRec to CatPositionRec. <3> 1/21/90 PP Fix bugs related to flashing and beeping while in scroll bar; "Select" button hilited evenif no selection was selected. <2.1> 12/15/89 prp Restore current port correctly. <2.0> 11/27/89 prp SetArrowCursor is now a Trap selector routine. <1.9> 11/16/89 prp Cancel dialog box uses 'Stop Search' button instead of cmd-period. MyFilter does not bring up cancel dialog but a fake returned item does. StopWatch and arrow cursor work correctly while cancel dialog is up. If initial volume not found, curVref still gets set correctly. <1.8> 10/30/89 prp • AcceptFile has additional vref argument. This allows choices from multiple disks to show up correclty. • Lock and Unlock sp->alList handle in order to not cause any purged handle referencing problems. • Handle CatSearch returning wrgVolTypeErr for AppleShare volumes where it is not supported. • Do not do AcceptFile of fastList explicitly. Reordering based on alFastList count. <1.7> 10/17/89 prp NewSFPGetFile is now released. No need to coerce arguments. <1.6> 10/14/89 ngk Changed call to NewSFPGetFile to not need coercing. <1.5> 10/13/89 prp Add support for folder 'Another One' selection. Works with NewSFPGetFile. <1.4> 10/2/89 prp Added support for searching all mounted volumes when user pushes 'TryHarder' button. <1.3> 9/18/89 prp SelectAlias has additional filtering parameters. <1.2> 9/6/89 prp Changes from CodeReview. <1.1> 8/11/89 prp Do not call CatSearch again if previous call has returned an eofErr. <1.0> 8/7/89 prp Initial Creation To Do: */ /*EASE$$$ READ ONLY COPY of file “alDialog.c” ** 2.1 prp 12/15/1989 Restore current port correctly. ** 2.0 prp 11/27/1989 SetArrowCursor is now a Trap selector routine. ** 1.9 prp 11/16/1989 Cancel dialog box uses 'Stop Search' button instead of ** cmd-period. MyFilter does not bring up cancel dialog but a fake ** returned item does. StopWatch and arrow cursor work correctly while ** cancel dialog is up. If initial volume not found, curVref still gets ** set correctly. ** 1.8 prp 10/30/1989 • AcceptFile has additional vref argument. This allows ** choices from multiple disks to show up correclty. • Lock and Unlock ** sp->alList handle in order to not cause any purged handle referencing ** problems. • Handle CatSearch returning wrgVolTypeErr for AppleShare ** volumes where it is not supported. • Do not do AcceptFile of fastList ** explicitly. Reordering based on alFastList count. ** 1.7 prp 10/17/1989 NewSFPGetFile is now released. No need to coerce ** arguments. ** 1.6 ngk 10/14/1989 Changed call to NewSFPGetFile to not need coercing. ** 1.5 prp 10/13/1989 Add support for folder 'Another One' selection. Works ** with NewSFPGetFile. ** 1.4 prp 10/02/1989 Added support for searching all mounted volumes when ** user pushes 'TryHarder' button. ** 1.3 prp 09/18/1989 SelectAlias has additional filtering parameters. ** 1.2 prp 09/06/1989 Changes from CodeReview. ** 1.1 prp 08/11/1989 Do not call CatSearch again if previous call has ** returned an eofErr. ** 1.0 prp 08/07/1989 Initial Creation ** END EASE MODIFICATION HISTORY */ /********************************************************************* * * File: alDialog.c * Project: Alias Manager * Contains: support for alias resolution through a dialog box * Written by: Prashant Patel * * Copyright 1989 by Apple Computer, Inc. * All Rights Reserved. * **********************************************************************/ /********************************************************************** *************** Public Include files ******************* *********************************************************************/ #include "Aliases.h" /********************************************************************** *************** Private Include files ******************* *********************************************************************/ #include "aliasPriv.h" #include "aliasDlogPriv.h" /********************************************************************** *************** External C Include files *************** *********************************************************************/ #ifndef __ERRORS__ #include #endif #ifndef __DIALOGS__ #include #endif #ifndef __LISTS__ #include #endif #ifndef __FONTS__ #include #endif #ifndef __RESOURCES__ #include #endif #ifndef __STANDARDFILE__ #include #endif #ifndef __TOOLUTILS__ #include #endif #ifndef __SCRIPT__ #include #endif /********************************************************************* ******** pseudo static Variables, since static not allowed *********** *********************************************************************/ /* This is a structure that holds variables that have a scope for this entire file. Since static variables are not allowed for stand-alone code resources, we will use a pointer to this struct as a way of accessing these variables. All local routines needing access to it will be passed a pointer to it. It will also be stored in RefCon of our dialog box record so that routines like myFilter can also access it. */ typedef struct { AliasPtrPriv aptr; // pointer to locked AliasRecord DialogPtr aliasDialog; // Pointer to alias dialog DialogPtr cancelDialog; // Pointer to cancel further search dialog SICNHandle alSICNHandle; // handle to SICN resource ControlHandle ButtonCH[kNumButtons]; // button control handles Rect nameRect; // Rectangle for names list Rect locationRect; // Rectangle for location display list ListHandle nameList; // handle to list of names ListHandle locationList; // handle to the list displaying location short selRow; // Current selection row in names list short prevSel; // previous selection row in names list short smallFontSize; // size of small font in which list entry text is drawn Boolean DoubleClick; // Flag to say that a double click on a list happened Boolean TryHarder; // Flag to say if in TryHarder mode Boolean firstTry; // Flag to say if TryingHard first time or not Boolean CSrch; // Flag to say if CatSearch available or not Boolean quitFlag; // Flag to say if client filter proc asked us to quit short firstVref; // volume ref num of first volume we searched short curVref; // current volume ref num of volume we are searching long curDir; // current directory we are searching long curIdx; // current directory index for the search CatPositionRec curPrec; // current CatSearch position record Str63 curFname; // current file name CInfoPBRec asyncCPB; // async I/O CPB record unsigned long startCount; // remember ticks when trying hard starts short curCnt; // current # of entries in alias list short curLim; // current # of entries allocated in alias list VCB *vcbPtr; // pointer to VCB entry CanonicalFileSpecHandle alList; // alias list buffer handle LongsHandle dirStack; // directory stack AliasFilterProcPtr fileFilter; // client supplied file filter proc ptr ModalFilterWithCallback modalFilter; // client supplied ModalDialog filter proc ptr Ptr yourDataPtr; // additional param to be passed to fileFilter & modalFilter StandardFileReply mySFreply; // reply record for CustomGetFile Boolean folderSelected; // Flag to say that a folder was selected during 'AnotherOne' } myStaticVars; typedef myStaticVars *myStaticPtr; // pointer to my static var record /********************************************************************* ******** forward declarations **************************************** *********************************************************************/ static OSErr Do_findNext(const myStaticPtr sp); static void DoneTryingHard(Boolean forEver, const myStaticPtr sp); static void NextVolumeSearch(const myStaticPtr sp); extern pascal OSErr AL_selectAliasWithDialog(const CanonicalFileSpec *fromFile, //I const Str31 fTypeName, //I short cnt, //I CanonicalFileSpecList alFastList,//I AliasFilterProcPtr aliasFilter, //I AliasHandlePriv Alias, //I/O CanonicalFileSpec *toFile, //O ModalFilterWithCallback filterProc, //I Ptr yourDataPtr); //I /********************************************************************* ******** Main Entry for dialog code. This has to be the first code *** ******** in this file. The code contained in this file gets loaded ** ******** dynamically only if needed. The first byte of the loaded *** ******** code is assumed to be the starting code for alias dialog. *** *********************************************************************/ pascal OSErr AL_mainEntryForDialog(const CanonicalFileSpec *fromFile, //I from file const Str31 fTypeName, //I descriptive name for file type short cnt, //I #of entries found during fast search CanonicalFileSpecList alFastList,//I fast search answer AliasFilterProcPtr aliasFilter, //I file filter proc pointer AliasHandlePriv Alias, //I/O alias record handle CanonicalFileSpec *toFile, //O returned toFile ModalFilterWithCallback filterProc, //I modal filter proc pointer Ptr yourDataPtr) //I additional param to be passed to filter procs { return (AL_selectAliasWithDialog (fromFile, fTypeName, cnt, alFastList, aliasFilter, Alias, toFile, filterProc, yourDataPtr)); } /********************************************************************* ******** Set the Font and size to our small, informational font ****** *********************************************************************/ static void DoSmFont() { TextFont(kSmallFont); TextSize(kSmallSize); } /********************************************************************* ******** Set the Font and size to the system font ******************** *********************************************************************/ static void DoDlgFont() { TextFont(0); TextSize(0); } /********************************************************************* ******** Draw one small icon from a SICN List ************************ *********************************************************************/ static void PlotSICN ( short theIndex, //I index into SICN list Rect *theRect, //I rect in which it is drawn const myStaticPtr sp) //I pointer to my static storage { BitMap theBits; // bitmap of the SICN SICNHandle theHandle; // handle to SICN list resource // set up the bitmap for the SICN to be drawn and copy it to the rect theHandle = sp->alSICNHandle; theBits.baseAddr = (Ptr) ((*theHandle)[theIndex]); theBits.rowBytes = 2; SetRect(&theBits.bounds, 0, 0, kSICNSize, kSICNSize); CopyBits(&theBits, &((sp->aliasDialog)->portBits), &theBits.bounds, theRect, srcCopy, NULL); } /********************************************************************* ******** Flash a button for user feedback **************************** *********************************************************************/ static void FlashButton(const ControlHandle button) //I button's control handle { long dummyCount; // dummy tick count HiliteControl (button, 1); // hiliting on Delay (8, &dummyCount); // delay for 8 ticks HiliteControl (button, 0); // hiliting off } /********************************************************************* ******** draw or hide the default outline of Select button *********** *********************************************************************/ static void DefaultOutline(Boolean on, //I outline on or off? const DialogPtr aliasDialog) //I my dialog box record pointer { Rect itemBox; // rectangle surrounding default item short DType; // Type of dialog item Handle DItem; // Handle to the dialog item GetDItem(aliasDialog, kI_SelectOutline, &DType, &DItem, &itemBox);// Get the item handle if (!on) PenMode(patBic); // clear it PenSize(3, 3); // Change pen to draw thick default outline FrameRoundRect(&itemBox, 16, 16); // Draw the outline PenNormal(); // restore initial state of pen } /********************************************************************* ******** Change Select, Cancel and Another One button states ********* *********************************************************************/ static void ChangeOthers(short hiliteState, //I new hilite state const myStaticPtr sp) //I pointer to my static storage { HiliteControl (sp->ButtonCH[kI_AnotherOne-1], hiliteState); // Another One button // If there is nothing to pick, don't activate Select button HiliteControl (sp->ButtonCH[kI_Select-1], (hiliteState == kButtonActive && sp->curCnt > 0) ? kButtonActive : kButtonInactive); // Select button to new state DefaultOutline ((hiliteState == kButtonActive && sp->curCnt > 0) ? kDrawOutline : kEraseOutline, sp->aliasDialog); // outline Select button HiliteControl (sp->ButtonCH[kI_Cancel-1], hiliteState); // Cancel button to new state } /********************************************************************* *************** Handle a list draw message ************************* *********************************************************************/ static void ListDrawMsg( Rect lRect, //I rect in which cell is drawn short lDataOffset, //I offset into cell data of the cell short lDataLen, //I length in bytes of cell data const ListHandle lHandle) //I list handle { ListEntry *theEntry; // ptr to entry we stored in the list DataHandle theCells; // Handle to cells Rect tempRect; // temporary rectangle Str63 aString; // String for mashing file name myStaticPtr sp; // pointer to my static data char masterFlags; // flags to remember before locking and unlocking handles sp = (myStaticPtr)(*lHandle)->userHandle; EraseRect(&lRect); // we are going to redraw it if (lDataLen > 0) { tempRect.top = lRect.top; tempRect.left = lRect.left; tempRect.bottom = lRect.bottom; tempRect.right = tempRect.left+kSICNSize; // boundry for SICN theCells = (*lHandle)->cells; masterFlags = HGetState ((Handle)theCells); // remember master flags HLock((Handle)theCells); theEntry = (ListEntry *) ((*theCells)+lDataOffset); // our list entry PlotSICN(theEntry->icon, &tempRect, sp); MoveTo(tempRect.right + kSpSICN, tempRect.bottom - kSIBase); // now draw text DoSmFont(); // small application font AL_copyPString (theEntry->fileName, aString); TruncString(lRect.right - (tempRect.right+kSpSICN), aString, smTruncEnd); // fit it in rectangle <6> DrawString(aString); DoDlgFont(); // back to default font HUnlock((Handle)theCells); HSetState((Handle)theCells, masterFlags); // restore original state } } // end of Alias_LDEF /********************************************************************* *************** LDEF procedure for name list ************************* *********************************************************************/ static pascal void Name_LDEF( short lMessage, //I operation to be performed Boolean lSelect, //I select the cell or not Rect lRect, //I rect in which cell is drawn Cell lCell, //I the cell which is operated on short lDataOffset, //I offset into cell data of the cell short lDataLen, //I length in bytes of cell data ListHandle lHandle) //I list handle { switch (lMessage) { case lDrawMsg: ListDrawMsg (lRect, lDataOffset, lDataLen, lHandle); if (lSelect) InvertRect(&lRect); break; case lHiliteMsg: InvertRect(&lRect); break; default: // ignore initialize and close break; } // end of switch } // end of Name_LDEF /********************************************************************* *************** LDEF procedure for location list ********************* *********************************************************************/ static pascal void Location_LDEF( short lMessage, //I operation to be performed Boolean lSelect, //I select the cell or not Rect lRect, //I rect in which cell is drawn Cell lCell, //I the cell which is operated on short lDataOffset, //I offset into cell data of the cell short lDataLen, //I length in bytes of cell data ListHandle lHandle) //I list handle { if (lMessage == lDrawMsg) { lRect.left += kSpSICN; // open folder looks better with offset ListDrawMsg (lRect, lDataOffset, lDataLen, lHandle); } // no need to handle any other messages, since picking not allowed in LocationList } // end of Location_LDEF /********************************************************************* *************** Get Icon ID given a directory ID ****************** *********************************************************************/ static short GetIconID(long dirID, //I directory ID of list entry unsigned short volType) //I current volume type { if (dirID != kVolRootDirID) return (kSIOpen); // open folder for non-root level directory else if (volType == kVolFloppy400K || volType == kVolFloppy800K || volType == kVolFloppy1400K) return (kSIFloppy); // root level is a folppy volume else return (kSIHard); // root level is hard disk volume } /********************************************************************* *************** add an entry to a list **************************** *********************************************************************/ static void Add_toList(short iconID, //I icon id for this list entry short vref, //I volume ref num for list entry long dirID, //I directory ID of list entry const StringPtr theString, //I text of list entry ListHandle theList) //I list handle { short theRow; // the row that we are going to add Point cSize; // Pointer to a cell in a list short len; // length of the string ListEntry theEntry; // entry to be added to the list cSize.h = 0; // Point to the correct column theRow = LAddRow(1, 32767, theList);// Add another row at the end of the list cSize.v = theRow; // Point to the row just added len = *theString; // prepare list entry theEntry.icon = iconID; theEntry.vRefNum = vref; theEntry.dirID = dirID; BlockMove (theString, theEntry.fileName, len+1); if (! (len & 1)) // force it even # of bytes ++len; // Place the entry in row just created LSetCell((Ptr)&theEntry, sizeof(theEntry)-(sizeof(theEntry.fileName)-1)+len, cSize, theList); } // end of routine Add_toList /********************************************************************* *************** select a given name row ************************** *********************************************************************/ static void SelectNameRow(short thisRow, //I name list row that should be selected const myStaticPtr sp) //I pointer to my static storage { Point selPt; SetPt (&selPt, 0, sp->selRow=thisRow); LSetSelect (TRUE, selPt, sp->nameList); } // end of routine SelectNameRow /********************************************************************* *************** display location for given name cell ************** *********************************************************************/ static void DisplayLoc(short thisRow, //I name list row that was selected const myStaticPtr sp) //I pointer to my static storage { OSErr err; // return code ListEntry theEntry; // a list entry Point theCell; // the cell to be retrieved short vref; // volume ref num of selected name long dirID; // parent dir ID of selected name Str63 localName; // name of a parent directory short len; // length of list entry Rect tempRect; // temporary rectangle LDelRow (0, 0, sp->locationList); // we will redraw location list LDoDraw (FALSE, sp->locationList); // do not display while building it len = sizeof (ListEntry); SetPt (&theCell, 0, thisRow); // get list entry of selected row LGetCell ((Ptr)&theEntry, &len, theCell, sp->nameList); vref = theEntry.vRefNum; // get its volume reference number dirID = theEntry.dirID; // get its parent directory ID // get names of all directories in its path and add them to location list while ((err = AL_findDirByID (vref, dirID, &dirID, localName)) == noErr) Add_toList (GetIconID(dirID, sp->aptr->volumeType), 0, 0, localName, sp->locationList); GetIndString (localName, kAliasResID, kDeskStrIdx); // get the "Desktop" display string Add_toList (kSIDesktop, 0, 0, localName, sp->locationList); // show the "Desktop" LDoDraw (TRUE, sp->locationList); // drawing on for next update tempRect = sp->locationRect; tempRect.right = tempRect.right - kScrMinOne; InvalRect (&tempRect); // invalidate to force an update } /********************************************************************* *************** display cancel dialog if needed ******************* *********************************************************************/ static void DisplayCancelIfNeeded(const myStaticPtr sp) //I pointer to my static storage { if (sp->startCount > 0 && (TickCount() >= (sp->startCount + kCancelWait))) { // put up cancel through stop search button dialog box sp->cancelDialog = GetNewDialog(kAlCancelDLOGID, NULL, (WindowPtr)-1); SetWRefCon (sp->cancelDialog, (long)sp); // store address of our static storage sp->startCount = 0; // remember that cancel dailog box is up AL_setArrowCursor(); // arrow cursor, so 'StopSearch' can be hit } } /********************************************************************** *************** Draw User Items ********************************** **********************************************************************/ static pascal void DrawUserItem(WindowPtr theDialog, //I pointer to my dialog window short itemNo) //I item number { myStaticPtr sp; // pointer to my static data ListHandle itemToChange; // item's handle Rect itemBox; // item's rectanglular box sp = (myStaticPtr) (GetWRefCon (theDialog)); // get our storage pointer switch (itemNo) { case kI_SelectOutline: // draw Select button outline DefaultOutline (sp->curCnt > 0 ? kDrawOutline : kEraseOutline, theDialog); break; case kI_NamesList: case kI_LocationList: if (itemNo == kI_NamesList) { itemBox = sp->nameRect; itemToChange = sp->nameList; } else { itemBox = sp->locationRect; itemToChange = sp->locationList; } // draw the names or location list outside rectangle and inside rectangle InsetRect(&itemBox, -1, -1); // Set for framing FrameRect(&itemBox); // Frame the main rectangle itemBox.right = itemBox.right - kScrMinOne;// Make room for the scroll bar on the right FrameRect(&itemBox); // Frame the inside rectangle LUpdate(theDialog->visRgn, itemToChange); // Update names list or location list break; default: break; } // end of itemNo switch } // end of DrawUserItem routine /********************************************************************** *************** dlgHook for NewSFPGetFile for folder selection **** **********************************************************************/ static pascal short FolderSFGetHook(short mySFItem, //I item number from SFPGetFile DialogPtr theDialog, //I SFPGetFile dialog record pointer myStaticPtr sp) { Handle itemToChange; // needed for GetDItem and SetCtlValue Rect itemBox; // needed for GetDItem short itemType; // needed for GetDItem Str255 buttonTitle; // needed for GetIndString if (mySFItem == sfHookFirstCall) { /* Before the dialog is drawn, our hook gets called with a -1. This gives us the opportunity to change 'open' title to 'Open Folder'. */ GetIndString(&buttonTitle, kAliasResID, kOpenFldrStrIdx); if (*buttonTitle != 0) { // if we really got the resource GetDItem(theDialog, getOpen, &itemType, &itemToChange, &itemBox); SetCTitle((ControlHandle)itemToChange,&buttonTitle); } } else { GetDItem(theDialog, kI_SelectFolder, &itemType, &itemToChange, &itemBox); if (sp->mySFreply.sfType == 0 && (Length(sp->mySFreply.sfFile.name) == 0)) { // nothing is selected, deselect 'Select Folder' button if ((*(ControlHandle)itemToChange)->contrlHilite == kButtonActive) HiliteControl ((ControlHandle)itemToChange, kButtonInactive); } else { // if 'Select Folder' not active, activate it if ((*(ControlHandle)itemToChange)->contrlHilite == kButtonInactive) HiliteControl ((ControlHandle)itemToChange, kButtonActive); } if (mySFItem == kI_SelectFolder) { // the user selected a folder sp->folderSelected = TRUE; // mark it as such, otherwise can't distinguish from real 'Cancel' mySFItem = getCancel; // tell SFPGetFile to get out } } return(mySFItem); } /********************************************************************** *************** Filter for ModalDialog call ********************** **********************************************************************/ static pascal Boolean MyFilter (DialogPtr theDialog, //I dialog record pointer EventRecord *theEvent, //I event record pointer short *itemHit) //O item hit { Point selPt; // current selection point char ch; // key-down character myStaticPtr sp; // pointer to my static data Boolean returnFromFilter; // answer from client's ModalDialog filter sp = (myStaticPtr) (GetWRefCon (theDialog)); // get our storage pointer if (sp->modalFilter != NULL) { // give client a chance to filter events returnFromFilter = ((ModalFilterWithCallback)(*(sp->modalFilter))) (theDialog, theEvent, itemHit, sp->yourDataPtr); if (returnFromFilter) return (TRUE); // client handled the event } switch (theEvent->what) { case mouseDown: selPt = theEvent->where; // Get position of click GlobalToLocal(&selPt); // Convert to local coordinates if (PtInRect(selPt,&sp->nameRect)) { // See if in names list sp->DoubleClick = LClick(selPt, theEvent->modifiers, sp->nameList); // select it if (selPt.h < (sp->nameRect.right - kScrMinOne)) { // not in scroll bar sp->prevSel = sp->selRow; // remember previous row to avoid unnecessary redraw SetPt (&selPt, 0, 0); // get the selection row > 0 if (LGetSelect(TRUE, &selPt, sp->nameList)) { // got the selection row sp->selRow = selPt.v; // newly selected row *itemHit = sp->DoubleClick ? kI_Select : kI_NamesList; //actual select or just a pick? return (TRUE); // we will handle the event } else if (sp->curCnt > 0) { // pick in an empty selection and there are entries SelectNameRow ((sp->curCnt-1), sp); // select the last entry in the list *itemHit = kI_NamesList;//actual select or just a pick? return (TRUE); // we will handle the event } } else { // click in scrollbar, return an item that does nothing *itemHit = kI_NameText; return (TRUE); } } else if (PtInRect(selPt,&sp->locationRect)) { // See if in display location list // do nothing for the contents region since this list is for display only. // if it is in the scroll bars, call LClick if (selPt.h >= (sp->locationRect.right - kScrMinOne)) (void) LClick(selPt, theEvent->modifiers, sp->locationList); } break; case keyDown: ch = theEvent->message & charCodeMask; // get the character switch (ch) { // which charcter was it? case kChrETX: // 'enter' or 'cr' means user has selected an alias case kChrCR: if ((*(sp->ButtonCH[kI_Select-1]))->contrlHilite == kButtonActive) { // disabled during TryHard mode *itemHit = kI_Select; // pretend that Select button was hit FlashButton (sp->ButtonCH[kI_Select-1]); // flash the Select button as feedback return(TRUE); // we will handle the event } case kChrESC: // 'ESC' or 'CMD-period' means user is canceling out case kChrPeriod: if (ch == kChrESC || (theEvent->modifiers & cmdKey)) { // 'ESC' or 'CMD-.' if ((*(sp->ButtonCH[kI_Cancel-1]))->contrlHilite == kButtonActive) { // cancel disabled during TryHarder mode *itemHit = kI_Cancel; // canceling out of alias selection dialog box FlashButton (sp->ButtonCH[kI_Cancel-1]);// flash the Cancel button as feedback return(TRUE); // we will handle the event } } break; default: break; } // end of character code switch break; // from keydown case case updateEvt: case nullEvent: if (theEvent->what == updateEvt && theDialog == theEvent->message) break; // could get an updateEvt for some other window instead of nullEvent if (sp->TryHarder) { // in TryingHarder mode if (sp->firstTry) {// are we seeing the TryHarder mode for the first time? Then // TryHarder mode was set programatically, pretend that TryHarder button was pushed *itemHit = kI_TryHarder; // pretend that TryHarder button was hit FlashButton (sp->ButtonCH[kI_TryHarder-1]); // flash the TryHarder button as feedback } else { *itemHit = kI_SearchInProgress; // TryHarder mode search is in progress } return(TRUE); // we will handle the event } break; defualt: break; } // end of switch statement return (FALSE); // Let ModalDialog handle the event } // end of MyFilter routine /********************************************************************** *************** Show empty dialog box initially ******************* *********************************************************************/ static void Display_aliasDialog (const Str31 fTypeName, //I descriptive name of file type const myStaticPtr sp) //I pointer to my static storage { Rect dataBounds; // Rect to setup the list Point cSize; // Pointer to a cell in a list FontInfo thisFontInfo; // info about application font Rect inRect; // inside rectangle for a list short Dtype; // dialog item type Handle Ditem; // dialog item handle Rect box; // dialog itm box register short i; // do loop index char *s; // temp char string pointer Str255 localName; // local name string sp->aliasDialog = GetNewDialog(kAliasDLOGID, NULL, (WindowPtr)-1);// Bring in the dialog resource SetWRefCon (sp->aliasDialog, (long)sp); // store address of our static storage AL_setArrowCursor(); // arrow cursor SetPort(sp->aliasDialog); // Prepare to add conditional text sp->alSICNHandle = (SICNHandle)(GetResource('SICN', kAliasResID)); // load all SICNs // display title with it's text and two parameters. // first is the descrptive name for the file type, second is the file name. if (Length(fTypeName) > 0) // client supplied file type name s = fTypeName; else GetIndString (s=localName, kAliasResID, sp->aptr->thisAliasKind == kFileAlias ? kDocStrIdx : kFldrStrIdx); ParamText (s, sp->aptr->fileName,'',''); // get all button's control handles for (i=1; i<=kNumButtons; i++) { GetDItem (sp->aliasDialog, i, &Dtype, &Ditem, &box); // get button control item sp->ButtonCH[i-1] = (ControlHandle) Ditem; } // get Select button outline box and install its userItem draw proc GetDItem (sp->aliasDialog, kI_SelectOutline, &Dtype, &Ditem, &inRect); SetDItem (sp->aliasDialog, kI_SelectOutline, Dtype, (Handle)&DrawUserItem, &inRect); // get name list userItem and install its userItem draw proc GetDItem (sp->aliasDialog, kI_NamesList, &Dtype, &Ditem, &sp->nameRect); SetDItem (sp->aliasDialog, kI_NamesList, Dtype, (Handle)&DrawUserItem, &sp->nameRect); // set userItem draw proc for name list and location list rectanlges GetDItem (sp->aliasDialog, kI_LocationList, &Dtype, &Ditem, &sp->locationRect); SetDItem (sp->aliasDialog, kI_LocationList, Dtype, (Handle)&DrawUserItem, &sp->locationRect); SetRect(&dataBounds, 0, 0, 1, 0); // Set list up, 1 column DoSmFont(); // get info about small font GetFontInfo(&thisFontInfo); // Get the current font sizes cSize.v = thisFontInfo.ascent + thisFontInfo.descent + thisFontInfo.leading; DoDlgFont(); // back to default font SetPt(&cSize, 0, (kSICNSize >= cSize.v) ? kSICNSize : cSize.v); // height of cell in the list // create name list inRect = sp->nameRect; inRect.right = inRect.right - kScrMinOne;// Make room for the scroll bar on the right sp->nameList = LNew(&inRect, &dataBounds, cSize, kAliasResID, sp->aliasDialog, TRUE, FALSE, FALSE, TRUE); // Make the list (*(sp->nameList))->selFlags = lOnlyOne + lNoNilHilite;// Set the attributes // create location list inRect = sp->locationRect; inRect.right = inRect.right - kScrMinOne;// Make room for the scroll bar on the right sp->locationList = LNew(&inRect, &dataBounds, cSize, kAliasResID, sp->aliasDialog, TRUE, FALSE, FALSE, TRUE); // Make the list (*(sp->locationList))->selFlags = lOnlyOne + lNoNilHilite;// Set the attributes // Patch the refcon fields in the ListHandles so that the dummy LDEFproc // can find the real, linked-in LDEFproc which is written in C. // Also, save the static storage pointer so that LDEF can access it. (*(sp->nameList))->refCon = &Name_LDEF; (*(sp->locationList))->refCon = &Location_LDEF; (*(sp->nameList))->userHandle = (Handle)sp; (*(sp->locationList))->userHandle = (Handle)sp; } // end of Display_dialog routine /********************************************************************* ******** done trying harder for now, provide feedback *************** *********************************************************************/ static void DoneTryingHard(Boolean forEver, //I TryHard done, is it for ever done? const myStaticPtr sp) //I pointer to my static storage { SysBeep(0); // beep to let the user know sp->TryHarder = FALSE; // set our global flag if (forEver && sp->dirStack != NULL) // dispose directory stack if done forever DisposHandle ((Handle)sp->dirStack); if (sp->startCount == 0 && sp->cancelDialog != NULL) { // a cancel dialog was put up DisposDialog(sp->cancelDialog); // Flush the cancel dialog out of memory sp->cancelDialog = NULL; sp->startCount = 1; // mark the flag } // if done forEver with TryingHard, make the button inactive, otherwise active. HiliteControl(sp->ButtonCH[kI_TryHarder-1], (forEver) ? kButtonInactive : kButtonActive); ChangeOthers(kButtonActive, sp); // all other buttons are now active if (sp->selRow == -1 && sp->curCnt > 0) { // nothing was selected yet SelectNameRow (0, sp); // select first entry by default DisplayLoc (0, sp); // display path of default selection } AL_setArrowCursor(); // back to arrow cursor } /********************************************************************* ******** Accept a file as an alias *********************************** *********************************************************************/ static OSErr AcceptFile (short vref, //I volume reference number long dirID, //I directory ID of the file const StringPtr fname, //I file name const myStaticPtr sp) //I pointer to my static storage { OSErr err; // result code Boolean returnFromFilter; // client wants to filter it or not? if (sp->fileFilter != NULL) { // client supplied file filter proc if ((err = AL_filterFile (vref, dirID, fname, sp->fileFilter, sp->yourDataPtr, (sp->CSrch) ? NULL : &sp->asyncCPB, kRealCPB, &returnFromFilter, &sp->quitFlag)) != noErr) return (err); if (returnFromFilter) // client says don't display it return (noErr); } if (sp->alList == NULL) { // allocate the slow search alias list buffer sp->alList = (CanonicalFileSpecHandle) (NewHandle(sizeof(CanonicalFileSpec) * sp->curLim)); if (sp->alList == NULL) return (MemError()); HLock((Handle)sp->alList); } else if (sp->curCnt >= sp->curLim) { // ran out of room in alias list buffer sp->curLim += kMaxCSrchEnt; // double its size HUnlock((Handle)sp->alList); SetHandleSize ((Handle)sp->alList, (sizeof(CanonicalFileSpec) * sp->curLim)); // grow alias list err = MemError(); HLock((Handle)sp->alList); if (err != noErr) { // could not extend block AL_displayAlert(kMem1StrIdx); return (err); } } if (AL_updateAList(vref, dirID, fname, // add an entry to alias list &sp->curCnt, sp->curLim, (*(sp->alList)))) { // room in the list & not duplicate Add_toList ((sp->aptr->thisAliasKind == kFileAlias) ? kSIDocument : kSIFolder, vref, dirID, fname, sp->nameList); // add it to Names List } return (noErr); } /********************************************************************* *************** Find file(s) or directory(s) by CatSearch ****** *********************************************************************/ static OSErr FindByCatSrch( short vref, //I volume reference number/WD ref const AliasPtrPriv aptr, //I alias record pointer long specBits, //I search specification mask long ioSearchTime, //I length of time to run search short lim, //I alias list buffer limit short *fcnt, //I/O current num of entries in buffer CanonicalFileSpecList flist,//O alias list buffer CatPositionRec *prec) //I/O CatSearch IO position record { OSErr err = paramErr; // result code, assume CatSrch not available CSParam cspb; // CatSearch parameter block CInfoPBRec cpb1, cpb2; // CatSearch setup catlog param blocks Str63 localName; // local temporary name FSSpec ans[kMaxCSrchEnt]; // maximum CatSearch return entries register short i; // for loop index // set up CatSearch parameter block cspb.ioNamePtr = cspb.ioOptBuffer = NULL; cspb.ioVRefNum = vref; cspb.ioMatchPtr = ans; cspb.ioReqMatchCount = (lim < kMaxCSrchEnt) ? lim : kMaxCSrchEnt; cspb.ioSpecBits = fsSBFlAttrib + specBits; if (aptr->thisAliasKind == kDirAlias && (specBits & fsSBFlFndrInfo)) // for files, type and creator are important but for folders they are not cspb.ioSpecBits -= fsSBFlFndrInfo; cspb.ioSpec1 = &cpb1; cspb.ioSpec2 = &cpb2; cspb.ioSearchTime = ioSearchTime; // length of time to run search // later on, may want to refine it depending upon performance cspb.ioCatPosition = *prec; // input CatSearch position record if (cspb.ioSpecBits & (fsSBFullName | fsSBPartialName)) { // by name specified AL_copyPString (aptr->fileName, localName); cpb1.hFileInfo.ioNamePtr = localName; // put name in first catalog param blk } else cpb1.hFileInfo.ioNamePtr = NULL; // name was not important cpb2.hFileInfo.ioNamePtr = NULL; cpb1.hFileInfo.ioFlAttrib = (aptr->thisAliasKind == kDirAlias) ? kDirMask : 0; cpb2.hFileInfo.ioFlAttrib = kDirMask;// only bit 4 is important if (cspb.ioSpecBits & fsSBFlCrDat) // creation date mask was specified cpb1.hFileInfo.ioFlCrDat = cpb2.hFileInfo.ioFlCrDat = aptr->fileCrDate; if (cspb.ioSpecBits & fsSBFlFndrInfo) { // for files, type and creator are important cpb1.hFileInfo.ioFlFndrInfo.fdType = aptr->fileType;; cpb1.hFileInfo.ioFlFndrInfo.fdCreator = aptr->fdCreator; // create the mask bits so that only type and creator are important. cpb2.hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF; cpb2.hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF; cpb2.hFileInfo.ioFlFndrInfo.fdFlags = 0; cpb2.hFileInfo.ioFlFndrInfo.fdLocation.h = 0; cpb2.hFileInfo.ioFlFndrInfo.fdLocation.v = 0; cpb2.hFileInfo.ioFlFndrInfo.fdFldr = 0; } err = PBCatSearch (&cspb, false); if (err == noErr || err == eofErr) { //if reached end of volume, it is ok for (i = 0; i < cspb.ioActMatchCount; ++i) { // load alias list buffer (void) AL_updateAList (vref, ans[i].parID, &ans[i].name, fcnt, lim, flist); if (*fcnt >= lim) // no room in return list break; } if (err == noErr) // new position not meaningful for eofErr or fnfErr *prec = cspb.ioCatPosition; // return the new position } return (err); } // end of FindByCatSrch routine /********************************************************************* ******** Perform next CatSearch ************************************** *********************************************************************/ static OSErr NextCatSrch(const myStaticPtr sp) //I pointer to my static storage { OSErr err, err2 = noErr; // result code CanonicalFileSpec nextFile; // next file that is found short fcnt = 0; // search count /* currently, CatSearch is by matching partial name, type, creator and creation date. Also, do one at a time. This gives user a chance to cancel out of search. curPrec maintains the current CatSearch position and hence search could be continued. */ err = FindByCatSrch (sp->curVref, sp->aptr, fsSBFlFndrInfo + fsSBFlCrDat, KMaxCSrchQuant, 1, &fcnt, &nextFile, &sp->curPrec); if (err == noErr || err == eofErr) { // this is ok, just reached end of volume while CatSearching if (fcnt != 0) // if nothing found, get out. otherwise, accept the alias err2 = AcceptFile(sp->curVref, nextFile.dirID, nextFile.fileName, sp); } return (err ? err : err2); } /********************************************************************* ******** Perform next asynchronous search **************************** *********************************************************************/ static OSErr NextAsyncSrch(const myStaticPtr sp) //I pointer to my static storage { OSErr err; // return code err = sp->asyncCPB.hFileInfo.ioResult; // result of last async search if (err == noErr) { // last async search was successful if (sp->asyncCPB.hFileInfo.ioFlAttrib & kDirMask) // found a directory if (sp->curIdx >= (kMaxDirStack-1)) { // ran out of directory stack AL_displayAlert(kMem2StrIdx); // too many dirs on volume err = memFullErr; // out of memory } else // add it to directory stack in order to search it later (*(sp->dirStack))[++sp->curIdx] = sp->asyncCPB.dirInfo.ioDrDirID; // does type, creator and creation date match? If yes, accept it as an alias. if (AL_attribMatches(sp->aptr, &sp->asyncCPB, kMatchFileNumber)) err = AcceptFile (sp->curVref, sp->asyncCPB.hFileInfo.ioFlParID, sp->asyncCPB.hFileInfo.ioNamePtr, sp); ++sp->asyncCPB.hFileInfo.ioFDirIndex; // search next file in the current dir } else if (err == fnfErr || err == dirNFErr || err == afpAccessDenied) { // these are valid errors. Either a directory was completely searched, or for // some reason the directory has disappeared or we don't have access to search it. if (sp->curIdx >= 0) { // any more directories remaining to be searched? sp->curDir = (*(sp->dirStack))[sp->curIdx--]; // next directory from stack sp->asyncCPB.hFileInfo.ioFDirIndex = 1; // start search at the beginning err = noErr; // force an async pending search } } else ; // ******************** serious error, get out ************** if (err==noErr) { // new I/O request if no fatal error sp->asyncCPB.dirInfo.ioDrDirID = sp->curDir;// replace file number with dirID (void) PBGetCatInfo (&sp->asyncCPB, TRUE); // issue an async CatInfo call } return (err); // error from last async call or memFullErr } /********************************************************************* ******** Find next matching alias via CatSearch or slow async search * *********************************************************************/ static OSErr Do_findNext(const myStaticPtr sp) //I pointer to my static storage { if (sp->CSrch) // CatSearch is available return (NextCatSrch(sp)); // do it else if (sp->asyncCPB.hFileInfo.ioResult != 1) // Did last async call complete? return (NextAsyncSrch(sp)); // yes, start the next one else return (noErr); // last async did not complete, just return } /********************************************************************* ******** User pushed the TryHarder button **************************** *********************************************************************/ static OSErr Do_TryHarder(const myStaticPtr sp) //I pointer to my static storage { OSErr err = noErr; // return code HiliteControl (sp->ButtonCH[kI_TryHarder-1], kButtonInactive); // make it inactive for now ChangeOthers(kButtonInactive, sp); // while trying hard, all other buttons are inactive if (sp->startCount == 1) { // flag says no cancel dialog up sp->startCount = TickCount(); // remember when try hard started SetCursor(*(GetCursor(watchCursor))); // cursor is in watch mode only before cancel dialog shows up } sp->TryHarder = TRUE; // set the flag if (sp->firstTry) { // if first time, need to allocate & initialize err = NextCatSrch(sp); if (err != noErr && err != eofErr) { // CatSearch not available sp->CSrch = FALSE; // remember that fact // allocate a directory stack to save all dirIDs found on the volume. // so each can be searched later on for matching alias. if (sp->dirStack == NULL) { // not already allocated sp->dirStack = (LongsHandle)(NewHandle(sizeof(long)*kMaxDirStack)); if (sp->dirStack == NULL) return (MemError()); } // allocated the directory stack (*(sp->dirStack))[0] = sp->curDir; // from root directory sp->curIdx = 0; // only root directory in the stack for now sp->asyncCPB.hFileInfo.ioResult = fnfErr; // this will start initial search sp->asyncCPB.hFileInfo.ioCompletion = NULL; // no completion routine sp->asyncCPB.hFileInfo.ioNamePtr = &sp->curFname;// returned name from GetCatInfo sp->asyncCPB.hFileInfo.ioFVersNum = 0; // keep GetCatInfo happy sp->asyncCPB.hFileInfo.ioVRefNum = sp->curVref; // volume to search err = NextAsyncSrch(sp);// start the async search } else if (err == eofErr) { // end of volume reached while CatSearching NextVolumeSearch (sp); // search the next volume err = noErr; // not a real error } sp->firstTry = FALSE; // from now on, no allocation and initialization unless next volume is searched } return (err); } /********************************************************************* *************** Initialize volume search statics **************** *********************************************************************/ static void Init_volSearchStatics(const myStaticPtr sp) //I pointer to my static storage { sp->firstTry = TRUE; // will be TryingHard the first time sp->CSrch = TRUE; // assume CatSearch available sp->quitFlag = FALSE; // assume client filter proc does not want to quit sp->curDir = kRootDirID; // current directory we are searching sp->curIdx = 0; // current directory index for the search sp->curPrec.initialize = 0; // initialize CatSearch } /********************************************************************* *************** Perform next mounted volume search **************** *********************************************************************/ static void NextVolumeSearch(const myStaticPtr sp) //I pointer to my static storage { short nextVref; // volume ref num of next volume to be searched for (;;) { if (sp->vcbPtr == NULL) { DoneTryingHard(kDoneForever, sp);// done forever TryingHard return; } else { nextVref = sp->vcbPtr->vcbVRefNum; sp->vcbPtr = (VCB *) sp->vcbPtr->qLink; if (sp->firstVref == nextVref) continue; else break; } } // we found a valid vrefNum that needs to be searched sp->curVref = nextVref; // this the current one we are searching sp->TryHarder = TRUE; // again trying harder on next volume Init_volSearchStatics (sp); // init volume search statics /* before we do the next volume search, make sure the cancel dialog box comes up if the timer has expired during (last CatSearch that returned eofErr) */ DisplayCancelIfNeeded (sp); // display cancel dialog box if needed return; } /********************************************************************* ******** User pushed the AnotherOne button *************************** *********************************************************************/ static void Do_AnotherOne(const myStaticPtr sp) //I pointer to my static storage { Point where; // display location of SFPGetFile dialog box SFTypeList typeList; // alias type passed to SFGetFile sp->folderSelected = FALSE; // when we come back from SFPGetFile, was a Folder really selected? // SFGetFile is linked here. User presumably knows where the aliased // entity is. Let him find it through modified SFPGetFile modal dialog. SetPt (&where, sp->aliasDialog->portRect.left+kSFGetHOffset, sp->aliasDialog->portRect.top+kSFGetVOffset); LocalToGlobal(&where); // put SFGetFile dialog box nicely offseted from alias dialog typeList[0] = sp->aptr->fileType; // match original alias type only if (sp->aptr->thisAliasKind == kDirAlias) { typeList[0] = kSelectNoFile; // show only folders CustomGetFile(NULL, 1, &typeList, &sp->mySFreply, kAlFldrSFGetID, where, FolderSFGetHook, NULL, NULL, NULL, sp); // put up the folder selection dialog } else CustomGetFile(NULL, 1, &typeList, &sp->mySFreply, kAlFileSFGetID, where, NULL, NULL, NULL, NULL, sp); // put up the file/volume selection dialog return; } /******************************************************************** *************** Initialize my static storage once *************** *********************************************************************/ static void Init_s(const myStaticPtr sp) //I pointer to my static storage { sp->aliasDialog = NULL; // Pointer to alias dialog sp->cancelDialog = NULL; // Pointer to cancel further search dialog sp->alSICNHandle = NULL; // handle to SICN resource sp->alList = NULL; // handle to alias list buffer sp->nameList = NULL; // handle to list of names sp->locationList = NULL; // handle to the list displaying location sp->DoubleClick = FALSE; // Flag to say that a double click on a list happened sp->TryHarder = FALSE; // Flag to say if in TryHarder mode sp->startCount = 1; // mark the flag to say that the cancel dialog box is not up sp->selRow = -1; // Current selection row in names list sp->prevSel = -1; // previous selection row in names list sp->dirStack = NULL; // handle to directory stack sp->curCnt = 0; // current count of alias list buffer sp->curLim = kMaxCSrchEnt; // current max entries allocated in alias list sp->vcbPtr = (VCB *)GetVCBQHdr()->qHead; // VCB Q header Init_volSearchStatics (sp); // init volume search statics } /********************************************************************* *************** Select an alias with dialog box ******************* *********************************************************************/ pascal OSErr AL_selectAliasWithDialog(const CanonicalFileSpec *fromFile, //I from file const Str31 fTypeName, //I descriptive name for file type short cnt, //I #of entries found during fast search CanonicalFileSpecList alFastList, //I fast search answer AliasFilterProcPtr aliasFilter, //I file filter proc pointer AliasHandlePriv Alias, //I/O alias record handle CanonicalFileSpec *toFile, //O returned toFile ModalFilterWithCallback filterProc, //I modal filter proc pointer Ptr yourDataPtr) //I additional param passed to filter procs { OSErr err = noErr; // result code short itemHit; // Get selection from ModalDialog register int i; // do loop index char masterFlags; // flags to remember before locking and unlocking handles Boolean ExitDialog = FALSE; // Flag used to exit the Dialog long fnum; // file number long parDirID; // parent directory ID Boolean needsUpdate; // alias record needs update or not? GrafPtr savePort; // save current port for restoring later register CanonicalFileSpec *fptr; // pointer into alias list /* the variables in structure myStaticVars are used by many routines in this file. They are meant as static variables. Since static is not allowed in stand-alone code resource, we are using pointer to this structure to simulate having static variables. None of these variables are needed across SelectAlias calls. They are valid while the dialog box is up. */ myStaticPtr sp; // pointer to our static storage if ((sp = (myStaticPtr)NewPtr(sizeof(myStaticVars))) == NULL) return (MemError()); // do initialization of our storage variables Init_s(sp); sp->fileFilter = aliasFilter; // remember client supplied file filter proc ptr sp->modalFilter = filterProc; // remember client supplied modal filter proc ptr sp->yourDataPtr = yourDataPtr; // remember additional param for both filter procs masterFlags = HGetState ((Handle)Alias); // remember master flags HLock((Handle)Alias); // lock the passed alias record sp->aptr = *Alias; // pointer to alias record as a variable // obtain volume reference number for the volume that we are searching if (cnt > 0) // found >=2 during fast search // remember the first volume that we will search sp->curVref = alFastList[0].vRefNum; else { err = AL_findVolume(sp->aptr, 0 /*no autoMount*/, &sp->curVref, &needsUpdate, NULL); // obtain curVref if (err == nsvErr) // could not find original aliase's volume, start with first in VCB chain sp->curVref = sp->vcbPtr->vcbVRefNum; else if (err != noErr) // fatal error goto EXIT; } sp->firstVref = sp->curVref; // remember the first volume that we searched // display initial dialog box GetPort (&savePort); // save the current port Display_aliasDialog(fTypeName, sp); // pass the descriptive file type name if (cnt > 0) { // was anything found during fast search? // fill entries of name list LDoDraw(FALSE, sp->nameList);// don't draw list while creating it for (i=0; iselRow, sp); } else { // nothing matching was found, kick in TryHarder search automatically sp->TryHarder = TRUE; // let MyFilter convert this flag into 'TryHarder' button hit } LDoDraw(TRUE, sp->nameList); // let us see list boxes initially LDoDraw(TRUE, sp->locationList); do { // Start of dialog handle loop ModalDialog(MyFilter, &itemHit); // Wait until an item is hit switch (itemHit) { case kI_Select: // Select Button OR Stop Search Button of cancel dialog if (sp->TryHarder && (sp->startCount == 0)) { // was Stop Search button hit? // canceling out of TryHard mode with cancel Dialog Box up? DoneTryingHard(kNotDoneForever, sp); // not done forever, user may push TryHarder again } else { // Select button of main dialog was hit ExitDialog = TRUE; // Exit the dialog when this selection is made fptr = &(*(sp->alList))[sp->selRow]; toFile->vRefNum = fptr->vRefNum; toFile->dirID = fptr->dirID; AL_copyPString (fptr->fileName, toFile->fileName); err = AL_findByName (toFile->vRefNum, toFile->dirID, toFile->fileName, &fnum, &parDirID); // make sure that the file still exists } break; case kI_Cancel: // Handle the Cancel Button ExitDialog =TRUE; // Exit the dialog when this selection is made err = userCanceledErr; // return user cancelling out of operation status break; case kI_TryHarder: // Handle the Try Harder Button if ((err = Do_TryHarder(sp)) != noErr) // start further search ExitDialog =TRUE; // Exit the dialog, serious error occurred break; case kI_SearchInProgress: // searching during TryHarder mode is in progress if (sp->quitFlag) { // client filter proc told us to quit current 'TryHard' seacrh DoneTryingHard(kNotDoneForever, sp); // not done forever, user may push TryHarder again sp->quitFlag = FALSE; // reset the flag } else { DisplayCancelIfNeeded (sp); // display cancel dialog box if needed // find the next matching alias and display it. If can't find any more, // provide feedback to the user. sp->TryHarder = (Do_findNext(sp) == noErr) ? TRUE : FALSE; if (! sp->TryHarder) // done searching this volume NextVolumeSearch(sp);// try searching next mounted volume } break; case kI_AnotherOne: // Handle the AnotherOne button Do_AnotherOne (sp); // do it! if (sp->mySFreply.sfGood || sp->folderSelected) { // return the selected file/folder as the returned alias BlockMove ((Ptr)&sp->mySFreply.sfFile, (Ptr)toFile, sizeof(CanonicalFileSpec)); ExitDialog = TRUE; // user chose the alias, now get out } // else user cancelled out of SFPGetFile dialog break; case kI_NamesList: // Handle a pick in the Names List if (sp->prevSel != sp->selRow) // display its location if a new row was picked DisplayLoc (sp->selRow, sp); break; case kI_LocationText: // if any of the presumably disabled items case kI_NameText: // nothing to do, just go back in loop case kI_Title: case kI_LocationList: break; default: // what was it? ExitDialog = TRUE; err = fnfErr; // alias not found break; } // end of switch statement } while (! ExitDialog); // Handle dialog items until exit selected EXIT: // release resources, dispose of handles and dialogs. if (sp->alSICNHandle != NULL) ReleaseResource ((Handle)sp->alSICNHandle); // release SICN resource if (sp->nameList != NULL) // names list LDispose (sp->nameList); if (sp->locationList != NULL) // location list LDispose (sp->locationList); if (sp->alList != NULL) // deallocate alias list buffer DisposHandle ((Handle)sp->alList); if (sp->startCount == 0 && sp->cancelDialog != NULL) // a cancel dialog was put up DisposDialog(sp->cancelDialog); // Flush the cancel dialog out of memory if (sp->aliasDialog != NULL) { DisposDialog(sp->aliasDialog); // dispose of our dialog SetPort(savePort); // restore the original port } DisposPtr ((Ptr)sp); // dispose of our static storage HUnlock((Handle)Alias); // unlock the alias record HSetState((Handle)Alias, masterFlags); // restore original state return (err); } // end of routine AL_selectAliasWithDialog /***************************** end of alDialog.c file *****************************/