mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-07-23 19:29:07 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1362 lines
58 KiB
C
1362 lines
58 KiB
C
/*
|
|
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 <errors.h>
|
|
#endif
|
|
#ifndef __DIALOGS__
|
|
#include <dialogs.h>
|
|
#endif
|
|
#ifndef __LISTS__
|
|
#include <Lists.h>
|
|
#endif
|
|
#ifndef __FONTS__
|
|
#include <Fonts.h>
|
|
#endif
|
|
#ifndef __RESOURCES__
|
|
#include <Resources.h>
|
|
#endif
|
|
#ifndef __STANDARDFILE__
|
|
#include <StandardFile.h>
|
|
#endif
|
|
#ifndef __TOOLUTILS__
|
|
#include <ToolUtils.h>
|
|
#endif
|
|
#ifndef __SCRIPT__
|
|
#include <Script.h>
|
|
#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; i<cnt; i++) // add matching entries to name scroll list
|
|
if ((err = AcceptFile (alFastList[i].vRefNum, alFastList[i].dirID, &alFastList[i].fileName, sp)) != noErr)
|
|
goto EXIT;
|
|
|
|
SelectNameRow (0, sp); // select the first entry by default
|
|
|
|
// fill location list with the path of first alias (the default selection)
|
|
DisplayLoc (sp->selRow, 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 *****************************/
|
|
|