Newsgroups: comp.sys.mac.programmer
Subject: Source Code: SFMultiGet
From: Manuel Veloso <veloso@husc9.harvard.edu>
Date: 30 Sep 92 09:25:42 EDT
Distribution: world
Organization: Harvard University
X-UserAgent: Nuntius v1.1.1d11
X-XXMessage-ID: <A6EF233FF0011817@humcr3.harvard.edu>
X-XXDate: Wed, 30 Sep 92 14:26:23 GMT

Hi there!

Here's some source code that I've always wanted, but never could find
online. It works, but since I wrote it last night it's robustness
should be questioned. It does seem to work, however. One thing I
realized this morning was that even thoughthere was no initialization
code, it still worked in ThC (how about that?)

	Improvements:
		? Filtering out the files already in the list. This doesn't really
		  bother me, but if you want, the fileFilter function is ready.
		? Scrollbar in the list. I was too lazy to make a scrollbar control,
		  handler, etc., and the automatic list scrollbar dies terribly.
		? Better System 6 behavior. Actually, I'm not sure what the thing
		  looks like under 6. Probably the auto-centering is off, the
		  button isn't hilited, & the enter keys don't work.
--------------------
#include <StandardFile.h>
#include <Resources.h>
#include <Memory.h>
#include <Lists.h>
#include <Packages.h>
#include <Files.h>
#include <Controls.h>

#define SFSaveDisk 	0x214
#define CurDirStore 0x398

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 cleanup(void);
void processData(void);

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);
}
	
enum
{
	okButton = 1,
	blank2,
	cancelButton,
	item1,
	ejectButton,
	driveButton,
	sfListBox,
	scrollBar,
	line1,
	blank10,
	filesBox,
	removeButton,
	addButton,
	line,
	kMyDialog = 128
};

ListHandle	gTheList;		// list of files selected
SFReply		gTheReply;		// the sf reply

/*
	Initializes the list within the sfdialog. Sets the useritem to the
	updateProc.
*/

pascal void initList(DialogPtr theDialog)
{
	Rect		rView, dataBounds;
	Point		cSize = {0, 0};
	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;
	gTheList = LNew(&rView, &dataBounds, cSize, 0, theDialog, true, false,
false, false);
	if (gTheList)
	{
		LDoDraw(true, gTheList);
		(*gTheList)->selFlags = lNoNilHilite + lUseSense + lOnlyOne;
		(*gTheList)->listFlags = lDoVAutoscroll;
		LActivate(true, gTheList);
		hiliteItem(theDialog, removeButton, 255);
		setItem(theDialog, filesBox, (Handle) myItem);
	}
	SetPort(oldPort);
	return;
}

pascal void cleanup(void)
{
	if (gTheList) LDispose(gTheList);
}

/*
	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, gTheList);
	SetPort(oldPort);
}

// false displays the file, true doesn't.

pascal Boolean myFileFilter(CInfoPBPtr pb)
{
	return false;
}

/*
	must return item #; if no number, nothing happens. I've remapped the
	add button to the okButton, and vice-versa to avoid lots of exess code.
*/

pascal short myDlgHook(short item, DialogPtr theDialog)
{
	switch (item)
	{
		case sfHookFirstCall:
			initList(theDialog);
			break;
		case okButton:			// maps to add!
			addData();
			item = addButton;
			break;
		case addButton:			// maps to ok!
			item = okButton;
			break;
		case removeButton:
			removeCells();
			hiliteItem(theDialog, removeButton, 255);
			break;
	}
	return item;
}

// false->handle the event || true->ignore the event

pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event,
short *itemHit)
{
	if (event->what == mouseDown)
	{
		if (FrontWindow() == theDialog)
		{
			GlobalToLocal(&(event->where));
			LClick(event->where, event->modifiers, gTheList);
			LocalToGlobal(&(event->where));
			hiliteItem(theDialog, removeButton, selected() ? 0 : 255);
		}
	}
	return false;
}

// are any cells selected?

Boolean selected(void)
{
	Cell	theCell = {0, 0};
	
	return LGetSelect(true, &theCell, gTheList);
}

// 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, gTheList))
	{
		LDelRow(1, theCell.v, gTheList);
	}
}

//	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};
	
	theCell.v = (**gTheList).dataBounds.bottom+1;
	theCell.v = LAddRow(1, theCell.v, gTheList);
	
	parID = *((long *)CurDirStore);
	vRefNum = -1 * (*(short *)SFSaveDisk);

	len = gTheReply.fName[0];
	LSetCell(&(gTheReply.fName[1]), len, theCell, gTheList);	// name

	NumToString(parID, text);
	len = text[0];
	theCell.h++;
	LSetCell(&(text[1]), len, theCell, gTheList);				// parent id
	
	parID = vRefNum;
	NumToString(parID, text);
	len = text[0];
	theCell.h++;
	LSetCell(&(text[1]), len, theCell, gTheList);				// vrefnum
}

//	just a test, to make sure all the files are there.

void processData(void)
{
	FSSpec	theFile;
	long	num;
	Str32	text;
	Cell	theCell = {0, 2};
	short	len;
	
	for (theCell.v = 0; theCell.v < (**gTheList).dataBounds.bottom;
theCell.v++)
	{
		len = 63;
		LGetCell((theFile.name)+1, &len, theCell, gTheList);
		theFile.name[0] = len;
		StringToNum(theFile.name, &(theFile.parID));
		theFile.vRefNum = theFile.parID;
		
		theCell.h--;
		len = 63;
		LGetCell((theFile.name)+1, &len, theCell, gTheList);
		theFile.name[0] = len;
		StringToNum(theFile.name, &(theFile.parID));
		
		theCell.h--;
		len = 63;
		LGetCell(theFile.name+1, &len, theCell, gTheList);
		theFile.name[0] = len;
		theCell.h = 2;
	}
}

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,
&gTheReply, kMyDialog, myFilterProc);

	if (gTheReply.good)
	{
		processData();
	}
	cleanup();
}
Newsgroups: comp.sys.mac.programmer