home *** CD-ROM | disk | FTP | other *** search
- /*
- This code to implement a standard getfile dialog with two lists
- is Copyright ©1992
-
- Manuel Veloso
- 9 High Rock Way #3
- Allston, MA 02134-2414
-
- It is freely available from many public FTP sites.
-
- Portions are Copyright © 1993, Kevin Hammond, Glasgow University.
-
- This code doesn't seem to handle aliases properly. KH
- */
-
- #include <StandardFile.h>
- #include <Resources.h>
- #include <Memory.h>
- #include <Lists.h>
- #include <Packages.h>
- #include <Files.h>
- #include <Controls.h>
-
- #include "mac.h"
-
- #pragma segment SFMultiGet
-
- #define SFSaveDisk 0x214 /* Volume number (negative) */
- #define CurDirStore 0x398 /* Current directory */
-
- enum
- {
- okButton = 1,
- blank2,
- cancelButton,
- item1,
- ejectButton,
- driveButton,
- sfListBox,
- scrollBar,
- line1,
- blank10,
- filesBox,
- removeButton,
- addButton,
- line,
- myScrollBar,
- kMyDialog = 128
- };
-
- ListHandle sfgTheList; // list of files selected
- SFReply sfgTheReply; // the sf reply
- ControlHandle sfgTheScrollBar; // the scrollbar
- static int sfgFileCount; // how many files are selected
-
-
- /*
- NOTE: the refCon of the control holds the # of files in the list AND the # of files
- that are visible. The refCon starts out as a negative #; when a file is added, the
- refCon is incremented. When refCon == 1, that means that scrolling must take place.
- When a file is removed, the refCon is decremented by 1. Presumably, when all files
- are removed the refCon == the original value.
- */
-
- pascal void setItem(DialogPtr theDialog, short item, Handle theProc);
- pascal void hiliteItem(DialogPtr theDialog, short item, short hiliteValue);
- pascal void getBox(DialogPtr theDialog, short item, Rect *box);
- void addData(void);
- void removeCells(void);
- Boolean selected(void);
- pascal void myItem(DialogPtr theDialog, short itemNumber);
- pascal void initList(DialogPtr theDialog);
- pascal Boolean myFileFilter(CInfoPBPtr pb);
- pascal short myDlgHook(short item, DialogPtr theDialog);
- pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event, short *itemHit);
- pascal void sfgCleanup(void);
- void processData(void);
- void handleScrollBar(DialogPtr, EventRecord*);
- pascal void scrollProc(ControlHandle theControl, short theCode);
-
- pascal void setItem(DialogPtr theDialog, short item, Handle theProc)
- {
- short itemType;
- Rect box;
- Handle theControl;
-
- GetDItem(theDialog, item, &itemType, &theControl, &box);
- SetDItem(theDialog, item, itemType, theProc, &box);
- }
-
- pascal void hiliteItem(DialogPtr theDialog, short item, short hiliteValue)
- {
- short itemType;
- Rect box;
- Handle theControl;
-
- GetDItem(theDialog, item, &itemType, &theControl, &box);
- HiliteControl((ControlHandle) theControl, hiliteValue);
- }
-
- pascal void getBox(DialogPtr theDialog, short item, Rect *box)
- {
- short itemType;
- Handle theControl;
-
- GetDItem(theDialog, item, &itemType, &theControl, box);
- }
-
- /*
- Initializes the list within the sfdialog. Sets the useritem to the
- updateProc.
- */
-
- pascal void initList(DialogPtr theDialog)
- {
- Rect rView, dataBounds;
- Point cSize = {0, 0};
- short temp;
- FontInfo fInfo;
- GrafPtr oldPort;
- Boolean good = false;
-
- GetPort(&oldPort);
- SetPort(theDialog);
- getBox(theDialog, filesBox, &rView);
- SetRect(&dataBounds, 0, 0, 3, 0);
- GetFontInfo(&fInfo);
- cSize.h = rView.right;
- cSize.v = fInfo.ascent + fInfo.descent + fInfo.leading;
- sfgTheList = LNew(&rView, &dataBounds, cSize, 0, theDialog, true, false, false, false);
- if (sfgTheList)
- {
- LDoDraw(true, sfgTheList);
- (*sfgTheList)->selFlags = lNoNilHilite + lUseSense + lOnlyOne;
- (*sfgTheList)->listFlags = lDoVAutoscroll;
- LActivate(true, sfgTheList);
- DisableButton(theDialog, removeButton);
- setItem(theDialog, filesBox, (Handle) myItem);
- }
- hiliteItem(theDialog, myScrollBar, 255);
- GetDItem(theDialog, myScrollBar, &temp, (Handle *) &sfgTheScrollBar, &dataBounds);
- SetCRefCon(sfgTheScrollBar, -((rView.bottom - rView.top)/cSize.v)); // # of lines in box, negativized
- SetCtlMin(sfgTheScrollBar, 0);
- SetCtlMax(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar));
- sfgFileCount = 0;
- SetPort(oldPort);
- return;
- }
-
- pascal void sfgCleanup(void)
- {
- if (sfgTheList) LDispose(sfgTheList);
- }
-
- /*
- Updates the list display, and does sundry drawing activities.
- */
-
- pascal void myItem(DialogPtr theDialog, short itemNumber)
- {
- Rect box;
- GrafPtr oldPort;
-
- GetPort(&oldPort);
- SetPort(theDialog);
-
- getBox(theDialog, filesBox, &box);
- InsetRect(&box, -1, -1);
- FrameRect(&box);
- getBox(theDialog, line, &box);
- FrameRect(&box);
- LUpdate(theDialog->visRgn, sfgTheList);
- SetPort(oldPort);
- }
-
- // false displays the file, true doesn’t.
- // Don't display invisible files
-
- static int IsDuplicateFile = false;
- char duplicateFName[256];
- long duplicatedirID;
- short duplicatevrefnum;
-
- void sfgProcessData();
-
-
- static int CheckForDuplicates(name,vrefnum,dirID)
- char *name;
- short vrefnum;
- long dirID;
- {
- char buff[32];
- if(*name == '\0')
- return(0);
-
- strcpy(buff,name);
- resolvealias(&buff,&vrefnum,&dirID,FALSE);
- if(strcmp(buff,duplicateFName)==0 &&
- duplicatedirID == dirID && duplicatevrefnum == vrefnum)
- {
- IsDuplicateFile = true;
- }
- return(0);
- }
-
-
- Boolean IsADuplicate(name,vrefnum,dirID)
- char *name;
- short vrefnum;
- long dirID;
- {
- IsDuplicateFile = false;
- pstrcopy(name,duplicateFName);
- p2cstr(duplicateFName);
- duplicatevrefnum = vrefnum;
- duplicatedirID = dirID;
- sfgProcessData(CheckForDuplicates);
- return (IsDuplicateFile);
- }
-
- /*
- must return item #; if no number, nothing happens. I've remapped the
- add button to the okButton, and vice-versa to avoid lots of excess code.
- */
-
- pascal short myDlgHook(short item, DialogPtr theDialog)
- {
- switch (item)
- {
- case sfHookFirstCall:
- initList(theDialog);
- DisableButton(theDialog, addButton);
- break;
-
- case okButton: // maps to add!
- addData();
- if(sfgFileCount>0)
- EnableButton(theDialog, addButton);
-
- if (GetCRefCon(sfgTheScrollBar)>0) hiliteItem(theDialog, myScrollBar, 0);
- else hiliteItem(theDialog, myScrollBar, 255);
- item = addButton;
- break;
-
- case addButton: // maps to ok!
- item = okButton;
- break;
-
- case removeButton:
- removeCells();
- if(sfgFileCount==0)
- DisableButton(theDialog, addButton);
-
- DisableButton(theDialog, removeButton);
- if (GetCRefCon(sfgTheScrollBar)>0) hiliteItem(theDialog, myScrollBar, 0);
- else hiliteItem(theDialog, myScrollBar, 255);
- break;
- }
- return item;
- }
-
- // false->handle the event || true->ignore the event
-
- pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event, short *itemHit)
- {
- char ch = (char) (event->message & charCodeMask); /* Convert to ASCII */
-
- switch (event->what)
- {
-
- case mouseDown:
- if (FrontWindow() == theDialog)
- {
- Rect theView;
- getBox(theDialog, filesBox, &theView);
- GlobalToLocal(&(event->where));
- if (PtInRect(event->where, &theView))
- {
- LClick(event->where, event->modifiers, sfgTheList);
- }
- else
- {
- getBox(theDialog, myScrollBar, &theView);
- if (PtInRect(event->where, &theView))
- {
- handleScrollBar(theDialog, event);
- }
- }
- LocalToGlobal(&(event->where));
- hiliteItem(theDialog, removeButton, selected() ? 0 : 255);
- }
- break;
-
-
- case keyDown:
- case autoKey:
- if((ch == 'l' || ch == 'L') && (event->modifiers & cmdKey) != 0)
- {
- *itemHit = addButton;
- return(true);
- }
- break;
-
- }
-
- return false;
- }
-
- // are any cells selected?
-
- Boolean selected(void)
- {
- Cell theCell = {0, 0};
-
- return LGetSelect(true, &theCell, sfgTheList);
- }
-
- // remove active cells. Even though there should be only one, I go thru them all anyway.
- void removeCells(void)
- {
- Cell theCell = {0, 0};
-
- while(LGetSelect(true, &theCell, sfgTheList))
- {
- --sfgFileCount;
- LDelRow(1, theCell.v, sfgTheList);
- SetCRefCon(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar) -1); // subtract
- SetCtlMax(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar)); // set scroll limit
- }
- }
-
- // ugly, but effective: the list is 3 columns wide, so I just stuff
- // the other 2 colums with the parID and the vRefNum, respectively.
-
- void addData(void)
- {
- long parID;
- short vRefNum;
- Str32 text;
- short len;
- Cell theCell = {0, 0};
-
- parID = *((long *)CurDirStore);
- vRefNum = -1 * (*(short *)SFSaveDisk);
-
- /* Don't allow duplicates */
- if(!IsADuplicate(sfgTheReply.fName,vRefNum,parID))
- {
- theCell.v = (**sfgTheList).dataBounds.bottom+1;
- theCell.v = LAddRow(1, theCell.v, sfgTheList);
-
- len = sfgTheReply.fName[0];
- LSetCell(&(sfgTheReply.fName[1]), len, theCell, sfgTheList); // name
-
- NumToString(parID, text);
- len = text[0];
- theCell.h++;
- LSetCell(&(text[1]), len, theCell, sfgTheList); // parent id
-
- parID = vRefNum;
- NumToString(parID, text);
- len = text[0];
- theCell.h++;
- LSetCell(&(text[1]), len, theCell, sfgTheList); // vrefnum
- SetCRefCon(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar) + 1); // add 1 file to count
- SetCtlMax(sfgTheScrollBar, GetCRefCon(sfgTheScrollBar)); // set scroll limit
- ++sfgFileCount;
- }
- }
-
- // just a test, to make sure all the files are there.
-
- void sfgProcessData(processFile)
- int (*processFile)();
- {
- FSSpec theFile;
- long num;
- Str32 text;
- Cell theCell = {0, 2};
- short len;
-
- for (theCell.v = 0; theCell.v < (**sfgTheList).dataBounds.bottom; theCell.v++)
- {
- char *fname;
- len = 63;
- LGetCell((theFile.name)+1, &len, theCell, sfgTheList);
- theFile.name[0] = len;
- StringToNum(theFile.name, &(theFile.parID));
- theFile.vRefNum = theFile.parID;
-
- theCell.h--;
- len = 63;
- LGetCell((theFile.name)+1, &len, theCell, sfgTheList);
- theFile.name[0] = len;
- StringToNum(theFile.name, &(theFile.parID));
-
- theCell.h--;
- len = 63;
- LGetCell(theFile.name+1, &len, theCell, sfgTheList);
- theFile.name[0] = len;
- theCell.h = 2;
- fname = (char *) p2cstr(theFile.name);
- resolvealias(&fname,&theFile.vRefNum,&theFile.parID,FALSE);
- processFile(fname,theFile.vRefNum,theFile.parID);
- }
- }
-
- /*
- void main(void)
- {
- Point where = {-1, -1};
-
- // note: the file filter can be omitted, if you want.
- SFPGetFile(where, "\pSelect files:", myFileFilter, -1, nil, myDlgHook, &sfgTheReply, kMyDialog, myFilterProc);
-
- if (sfgTheReply.good)
- {
- processData();
- }
- sfgCleanup();
- }
- */
-
- void handleScrollBar(DialogPtr theDialog, EventRecord *event)
- {
- short thePart, oldVal;
- Point pt = (*event).where;
- ControlHandle theControl;
-
- if ((thePart = FindControl(pt, theDialog, &theControl)) == inThumb)
- {
- oldVal = GetCtlValue(theControl);
- thePart = TrackControl(theControl, pt, nil);
- LScroll(0, GetCtlValue(theControl) - oldVal, sfgTheList);
- }
-
- /* Added check for disabled control -- KH */
- else if (thePart != 0)
- {
- thePart = TrackControl(theControl, pt, (ProcPtr) scrollProc);
- }
- }
-
- pascal void scrollProc(ControlHandle theControl, short theCode)
- {
- short theValue = GetCtlValue(theControl);
- short maxValue = GetCtlMax(theControl);
- switch (theCode)
- {
- case inPageDown:
- case inDownButton:
- theValue++;
- LScroll(0, 1, sfgTheList);
- break;
- case inPageUp:
- case inUpButton:
- LScroll(0, -1, sfgTheList);
- theValue--;
- break;
-
- /* Added missing case -- KH */
- case 0:
- return;
- }
-
- /* Original didn't check for out-of-range values!! KH */
- if(theValue <= maxValue && theValue >= 0)
- SetCtlValue(theControl, theValue);
- }
-