home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-07-24 | 39.4 KB | 1,067 lines | [TEXT/CWIE] |
- // --------------------------------------------------------------------------------------------
- // UGetMulltipleFiles - An Add Files utility class
- // By David Hirsch
- // please read the "Read Me" file.
- //
- // Notes:
- // 1) The List Manager's list that we display in the dialog box starts with zero for the
- // first item, while the LArray that holds the FSSpec records starts with 1.
- //
- // --------------------------------------------------------------------------------------------
-
- #include "UGetMultipleFiles.h"
- #include <string.h>
- #include <LString.h>
- #include "GetDirItems.h"
- #include <UDrawingState.h>
- #include "patch.h"
-
- // --------------------------------------------------------------------------------------------
- // Global variables
- // --------------------------------------------------------------------------------------------
- ListHandle gToolboxList = nil;
- UniversalProcPtr patchCode = nil;
- Boolean needToFixButtons; // this is so we can delay one "cycle"
- Boolean tabKludge = false;
-
- // --------------------------------------------------------------------------------------------
- // Static class variables
- // --------------------------------------------------------------------------------------------
-
- ListHandle UGetMultipleFiles::sAddedListH = nil;
- DialogPtr UGetMultipleFiles::sDialogP = nil;
- StandardFileReply UGetMultipleFiles::sReply;
- LArray *UGetMultipleFiles::sTheFSpecs = nil;
- LArray *UGetMultipleFiles::sNixFiles = nil;
- short UGetMultipleFiles::sNumTypes = -1;
- SFTypeList UGetMultipleFiles::sTypeList = {};
- LFSSpecArrayComp *UGetMultipleFiles::sComparatorP = nil;
- Boolean UGetMultipleFiles::sNeedToRebuild = false;
- Boolean UGetMultipleFiles::sAllowConversion = true;
- Boolean UGetMultipleFiles::sShowFolders = true;
- Boolean UGetMultipleFiles::sAddFolders = false;
- short UGetMultipleFiles::sKeyPressed = 0;
-
- // --------------------------------------------------------------------------------------------
- // UGetMultipleFiles
- // Default constructor; calls detailed constructor, but without a prompt or typelist.
- // --------------------------------------------------------------------------------------------
- UGetMultipleFiles::UGetMultipleFiles()
- {
- UGetMultipleFiles((unsigned char *)"", (short) -1, (unsigned long *) nil, nil, false, true, false);
- }
-
- // --------------------------------------------------------------------------------------------
- // UGetMultipleFiles - main constructor.
- // --------------------------------------------------------------------------------------------
- UGetMultipleFiles::UGetMultipleFiles(Str255 prompt, short numTypes,
- SFTypeList typeList, LArray *inFileList,
- Boolean inAllowConversion, Boolean inShowFolders,
- Boolean inAddFolders)
- {
- Point myPoint = {-1, -1}; // have dialog appear centered
- FileFilterYDUPP theFileFilterYDUPP;
- DlgHookYDUPP theDlgHookYDUPP;
- ModalFilterYDUPP theModalFilterYDUPP;
- ActivateYDUPP theActivateYDUPP;
- PatchRouterUPP thePatchRouterUPP;
- FSSpec oneFSSpec;
- Int16 activateListArray[3];
- Handle patchResource;
- dataHolderType myData;
-
- if (sComparatorP == nil)
- sComparatorP = new LFSSpecArrayComp(); // create comparator for the FSSpec array
- if (sTheFSpecs == nil)
- sTheFSpecs = new LArray(sizeof(FSSpec), sComparatorP); // create the FSSpec array
- sTheFSpecs->SetKeepSorted(true); // sort the array
-
- myData.whichFocused = kUserItem_FileList; // for focus routines; begins focused on Toolbox List
- sNixFiles = inFileList;
- if ((sNixFiles != nil))
- sNixFiles->SetComparator(sComparatorP);
-
- sNumTypes = numTypes; // store the numTypes parameter
- for (short j=0; j <= numTypes - 1; j++) // store each type
- sTypeList[j] = typeList[j];
-
- LString::CopyPStr((unsigned char *)prompt, (unsigned char *)oneFSSpec.name); // send in the prompt disguised as the first FSSpec
- sTheFSpecs->InsertItemsAt(1, (sTheFSpecs->GetCount()) + 1, &oneFSSpec);
-
- theDlgHookYDUPP = NewDlgHookYDProc(myDialogHook);
- theModalFilterYDUPP = NewModalFilterYDProc(myModalFilter);
- theFileFilterYDUPP = NewFileFilterYDProc(myFileFilter);
- theActivateYDUPP = NewActivateYDProc(myActivateProc);
- activateListArray[0] = 2;
- activateListArray[1] = kUserItem_FileList;
- activateListArray[2] = kUserItem_AddedList;
- // UDesktop::Deactivate(); //DMH 4.9.97
- ::InitCursor(); //DMH 4.9.97
- sAllowConversion = inAllowConversion;
- sShowFolders = inShowFolders;
- sAddFolders = inAddFolders;
-
-
- patchResource = GetResource('patc', 0);
- if (patchResource) {
- HLock(patchResource);
- HNoPurge(patchResource);
-
- thePatchRouterUPP = NewPatchRouterProc((ProcPtr)*patchResource);
- CallPatchRouterProc(thePatchRouterUPP, kInstall, &gToolboxList);
-
- gToolboxList = nil;
- ::CustomGetFile(theFileFilterYDUPP, -1, NULL, &sReply, kDLOG_OpenMultiple, myPoint,
- theDlgHookYDUPP, theModalFilterYDUPP, activateListArray, theActivateYDUPP, (void *) &myData);
- gToolboxList = nil;
-
- CallPatchRouterProc(thePatchRouterUPP, kRemove, &gToolboxList);
- DisposeRoutineDescriptor(thePatchRouterUPP);
- }
- else {
- SysBeep(1);
- }
- // UDesktop::Activate(); //DMH 4.9.97
- DisposeRoutineDescriptor(theDlgHookYDUPP);
- DisposeRoutineDescriptor(theModalFilterYDUPP);
- DisposeRoutineDescriptor(theActivateYDUPP);
- DisposeRoutineDescriptor(theFileFilterYDUPP);
-
- // If we weren't allowing conversion/checking, and we got a cancel message, but
- // we never deleted the files, then what really happened was that the user
- // in fact clicked the Done button, and the Dialog Hook sent the cancel message
- // to get around the conversion/checking stuff. Reset the reply field.
- if ((!sAllowConversion) && !(sReply.sfGood) && (sTheFSpecs->GetCount() > 0)) {
- sReply.sfGood = true;
- }
-
- // Kludge for NOW Direct Open feature of SuperBoomerang - Direct Open does not
- // fill in parID and vRefNum in the dialog hook which UGetMultipleFiles relies
- // on to work its magic. Fortunately, Direct Open does fill in all FSSpec
- // fields in the reply record. if there is only one FSSpec in the mTheFSpecs array
- // and its parID and vRefNum are both 0, replace it with the FSSpec in the reply record.
- if (sTheFSpecs->GetCount() == 1) {
- sTheFSpecs->FetchItemAt(1, &oneFSSpec);
- if ( (0 == oneFSSpec.parID) && (0 == oneFSSpec.vRefNum) ) {
- sTheFSpecs->RemoveItemsAt(1, 1); // remove the incomplete FSSpec
- sTheFSpecs->InsertItemsAt(1, 1, &sReply.sfFile);
- }
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // UGetMultipleFiles - main destructor.
- // --------------------------------------------------------------------------------------------
- UGetMultipleFiles::~UGetMultipleFiles()
- {
- if (sComparatorP != nil) {
- delete sComparatorP;
- sComparatorP = nil;
- }
- if (sTheFSpecs != nil) {
- delete sTheFSpecs;
- sTheFSpecs = nil;
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // GetFSSpecs - accessor for the FSSpec LArray.
- // --------------------------------------------------------------------------------------------
- LArray* UGetMultipleFiles::GetFSSpecs()
- {
- return sTheFSpecs;
- }
-
- // --------------------------------------------------------------------------------------------
- // GetSFReply - accessor for the reply record.
- // --------------------------------------------------------------------------------------------
- StandardFileReply UGetMultipleFiles::GetSFReply()
- {
- return sReply;
- }
-
-
- // --------------------------------------------------------------------------------------------
- // myModalFilter - Modal Dialog calls this just after the Standard File Package's filter
- // This routine was taken from the Apple Macintosh Developer Technical Support
- // Standard File Application, which I downloaded from Apple's web site, and modified.
- // --------------------------------------------------------------------------------------------
- pascal Boolean UGetMultipleFiles::myModalFilter (DialogPtr theDialogP, EventRecord *event,
- short *itemHit, void *ioParam)
- {
-
- Rect itemRect;
- Point clickPos;
- Handle itemHandle;
- Boolean firstTimeThrough = true;
-
- if (GetWRefCon(theDialogP) != sfMainDialogRefCon)
- return false;
- if ((*event).what == mouseDown) {
- clickPos = (*event).where;
- GlobalToLocal(&clickPos);
- GetDialogItem(theDialogP, kUserItem_AddedList, userItem, &itemHandle, &itemRect);
- if (PtInRect(clickPos, &itemRect)) {
- if (::LClick(clickPos, (*event).modifiers, sAddedListH)) {
- RemoveFromList();
- sNeedToRebuild = true;
- }
- *itemHit = kUserItem_AddedList;
- return true;
- }
- }
- if ((*event).what == keyDown) {
- Int16 theKey = (*event).message & charCodeMask;
- if (theKey == '\t') {
- if ((((dataHolderType *)ioParam)->whichFocused) == kUserItem_AddedList)
- ((dataHolderType *)ioParam)->whichFocused = kUserItem_FileList;
- else
- ((dataHolderType *)ioParam)->whichFocused = kUserItem_AddedList;
- }
- if (theKey == kHome ||
- theKey == kEnd ||
- theKey == kUpArrow ||
- theKey == kDownArrow ||
- theKey == kPageUp ||
- theKey == kPageDown) {
- sKeyPressed = theKey;
- }
- }
- return false;
- }
-
- // --------------------------------------------------------------------------------------------
- // myFileFilter - This dictates which files to show in the list
- // --------------------------------------------------------------------------------------------
- pascal Boolean UGetMultipleFiles::myFileFilter (CInfoPBPtr pb, void *ioParam)
- {
- #pragma unused(ioParam)
-
- // extract the FSSpec from the CInfoPBPtr
- FSSpec tempSpec;
- LStr255 nameStr(pb->hFileInfo.ioNamePtr);
- UInt8 lastNamePos = nameStr.ReverseFind(':');
- nameStr.Remove(1, lastNamePos);
- OSErr theErr = ::FSMakeFSSpec(pb->hFileInfo.ioVRefNum, pb->hFileInfo.ioFlParID, nameStr, &tempSpec);
- if (theErr != noErr)
- return false;
-
- if (!sAddFolders) { // Don't need this if adding folders, since we're treating them like files!
- if (sShowFolders && IsFolder(pb)) { // if we're showing folders and this is a folder
- return false; // then show it
- }
- }
-
- if (!IsFolder(pb) && !TypeInList( pb->hFileInfo.ioFlFndrInfo.fdType )) { // if it's not a folder and the type isn't in the list
- return true; // then don't show it
- } // Note: we need this check for when we're adding folders and showing them
-
- // see if it's in the list of added files
- if (sTheFSpecs->FetchIndexOf(&tempSpec) != sTheFSpecs->index_Bad) // if it is in the added list
- return true; // then don't show it
- else {
- if (sNixFiles == nil) // don't suppress any
- return false;
- // see if it's in the list of excluded files
- else if (sNixFiles->FetchIndexOf(&tempSpec) != sNixFiles->index_Bad) // if it is in the exclude list
- return true; // then don't show it
- else
- return false;
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // myActivateProc - Modal Dialog calls this when activating or deactivating a list box
- // --------------------------------------------------------------------------------------------
- pascal void UGetMultipleFiles::myActivateProc (DialogPtr theDialogP, short itemNum,
- Boolean activating, void *ioParam)
- {
- dataHolderType *myData = (dataHolderType *) ioParam;
- StColorPortState theState(theDialogP);
- RGBColor theBackColor;
- Rect itemRect;
- short itemKind;
-
- if (GetWRefCon(theDialogP) != sfMainDialogRefCon)
- return;
- ::PenNormal();
- ::PenSize(2, 2);
- if (itemNum == kUserItem_AddedList) {
- GetDialogItem(theDialogP, itemNum, &itemKind, userItem, &itemRect);
- ::InsetRect(&itemRect, -4, -4);
- if (activating) {
- ::ForeColor(blackColor);
- ::FrameRect(&itemRect);
- ::LActivate(true, sAddedListH);
- EnsureSelection(kUserItem_AddedList);
- myData->whichFocused = kUserItem_AddedList;
- } else {
- ::LActivate(false, sAddedListH);
- ::PenNormal();
- ::PenSize(2, 2);
- ::GetBackColor(&theBackColor);
- ::RGBForeColor(&theBackColor);
- ::FrameRect(&itemRect);
- myData->whichFocused = kUserItem_FileList;
- }
- } else {
- if (activating) {
- EnsureSelection(kUserItem_FileList);
- tabKludge = true;
- }
- }
- needToFixButtons = true;
- }
-
- #include <stdlib.h>
- // --------------------------------------------------------------------------------------------
- // myDialogHook - the Standard File Package calls this routine just after myModalFilter.
- // --------------------------------------------------------------------------------------------
- pascal short UGetMultipleFiles::myDialogHook (short item, DialogPtr theDialogP, void *ioParam)
- {
- Cell curSelCell = {0,0};
- Cell nextCell;
- Boolean result;
- dataHolderType *myData = (dataHolderType *) ioParam;
- static Boolean onceThrough;
- static Boolean haveRebuilt = false;
- Rect itemRect;
- Handle itemHandle;
- short itemKind;
- FSSpec oneFSSpec;
- UserItemUPP theDLUserItemUPP = nil;
-
- if (GetWRefCon(theDialogP) != sfMainDialogRefCon)
- return item;
-
- switch (item) {
- case sfHookFirstCall: // gets called just before the dialog is made
- onceThrough = false;
- needToFixButtons = true;
- ListHandle temp = gToolboxList; // save the Toolbox ListHandle
- sAddedListH = MyCreateTextListInDialog(theDialogP, kUserItem_AddedList); // make the added list
- gToolboxList = temp; // replace the Toolbox LH that was overwritten by our call of LNew
- GetDialogItem(theDialogP, kUserItem_AddedList, userItem, &itemHandle, &itemRect);
- theDLUserItemUPP = NewUserItemProc(&(MyDrawListItem)); // install the draw routine for
- // the list of added files
- SetDialogItem(theDialogP, kUserItem_AddedList, userItem, (Handle)theDLUserItemUPP, &itemRect);
-
- sDialogP = theDialogP; // store the dialog pointer
- if (!sAddFolders) {
- HideDialogItem(sDialogP, kStdButton_Select);
- GetDialogItem(sDialogP, kStdButton_Select, btnCtrl, &itemHandle, &itemRect);
- ::SizeWindow(sDialogP, sDialogP->portRect.right - sDialogP->portRect.left,
- sDialogP->portRect.bottom - sDialogP->portRect.top - (itemRect.bottom - itemRect.top), true);
- }
- SetEnable(sfItemOpenButton, true); // Add button is active, no highlighting
- SetEnable(kStdButton_Done, true); // Done button is active, no highlighting
- SetEnable(kStdButton_Remove, false); // Remove button is inactive
- SetEnable(kStdButton_RemoveAll, false); // Remove all button is inactive
-
- SetEnable(kStdButton_AddAll, true); // Add all button is active, no highlighting
- sTheFSpecs->FetchItemAt(1, &oneFSSpec); // Extract the prompt from the first FSSpec
- sTheFSpecs->RemoveItemsAt(1, 1);
- GetDialogItem(theDialogP, kStaticText_Prompt, &itemKind, &itemHandle, &itemRect);
- SetDialogItemText(itemHandle, oneFSSpec.name);
-
- onceThrough = true;
-
- return sfHookNullEvent;
- break;
- case sfHookLastCall: // called just after we're done with the dialog
- DisposeRoutineDescriptor(theDLUserItemUPP);
- LDispose(sAddedListH);
- if ((sTheFSpecs->GetCount() > 0) && (!sAllowConversion)) {
- // since we're supressing checking, we won't be sending an sfItemOpenButton
- // "message", that would cause the Standard File Package to reset the current
- // volume and directory to that contained in the sReply.sfFile field.
- // We'll therefore set it by hand.
- FSSpec *oneSpec = (FSSpec *) sTheFSpecs->GetItemPtr(1);
- SetCurrentVolume(oneSpec->vRefNum);
- SetCurrentDirectory(oneSpec->parID);
- }
- return sfHookNullEvent;
- break;
- case sfItemCancelButton:
- sTheFSpecs->RemoveItemsAt(sTheFSpecs->GetCount(), 1); // remove all files from array
- FixButtons(theDialogP, ioParam);
- return sfItemCancelButton;
- break;
-
- case kUpArrowPlusCO:
- case kDownArrowPlusCO:
- needToFixButtons = true;
- break;
-
- case sfHookGoToDesktop:
- case sfHookFolderPopUp:
- case sfItemVolumeUser:
- case sfHookOpenFolder:
- sNeedToRebuild = true;
- needToFixButtons = true;
- break;
-
- case kUserItem_FileList:
- FixButtons(theDialogP, ioParam);
- return sfHookSetActiveOffset + kUserItem_FileList;
- break;
-
- case sfItemOpenButton:
- case kStdButton_Select:
- AddOneToList(sReply.sfFile.name, sReply.sfFile.parID, sReply.sfFile.vRefNum);
- result = LGetSelect(true, &curSelCell, gToolboxList);
- if (result) { // if there was something selected
- Boolean isLast = (curSelCell.v == (**gToolboxList).dataBounds.bottom - 1);
- if (sReply.sfFile.parID != fsRtParID) { // and it wasn't a volume
- LDelRow(1, curSelCell.v, gToolboxList); // delete that cell
- } else { // it was a volume, so we didn't delete it - increment the selection instead
- LSetSelect(false, curSelCell, gToolboxList);
- curSelCell.v++;
- }
- if (isLast) // if the cell was the last one
- nextCell.v = (**gToolboxList).dataBounds.bottom - 1;
- else // else it was not the last cell
- nextCell.v = curSelCell.v;
-
- nextCell.h = 0;
- LSetSelect(true, nextCell, gToolboxList);
- LAutoScroll(gToolboxList);
- }
- needToFixButtons = true; // if we FixButtons now, the Reply field will not have been changed yet.
- // this will delay things by one cycle.
- return sfHookNullEvent;
- break;
-
- case kStdButton_Done:
- if (sAllowConversion)
- return sfItemOpenButton; // nothing to do here; everything is in the FSSpec array
- else
- return sfItemCancelButton; // since we're supressing checking, we fake a cancel messge
- // we'll know in the calling function that it was fake
- // because there will still be files in the array.
- break;
- case kStdButton_Remove:
- RemoveFromList();
- needToFixButtons = true;
- haveRebuilt = true;
- return sfHookRebuildList;
- break;
- case kStdButton_AddAll:
- HLock((Handle)sAddedListH);
- AddAllToList(!GetEnabled(kDesktopButton)); // if Desktop btn is enabled, we're not at the Desktop level
- HUnlock((Handle)sAddedListH);
- needToFixButtons = true;
- haveRebuilt = true;
- return sfHookRebuildList;
- break;
- case kStdButton_RemoveAll:
- RemoveAllFromList();
- needToFixButtons = true;
- haveRebuilt = true;
- return sfHookRebuildList;
- break;
- case kUserItem_AddedList:
- Point theCell;
- theCell.v = theCell.h = 0;
- if ((sTheFSpecs->GetCount() != 0) && (LGetSelect(true, &theCell, sAddedListH))) {
- // list is not empty & something is selected, so enable Remove & Remove All
- SetEnable(kStdButton_Remove, true); // enable remove button
- SetEnable(kStdButton_RemoveAll, true); // enable remove all button
- }
- FixButtons(theDialogP, ioParam);
- return sfHookSetActiveOffset + kUserItem_AddedList;
- break;
- case sfHookNullEvent:
- // Key actions have to be done first, then rebuilding the list if necessary,
- // and lastly, fixing button states, because that depends on the outcome of
- // the first operations.
- if (sKeyPressed > 0) {
- if (myData->whichFocused == kUserItem_AddedList) {
- DoListKey(sKeyPressed, sAddedListH);
- } else
- DoListKey(sKeyPressed, gToolboxList);
- sKeyPressed = 0;
- } else if (sNeedToRebuild) {
- sNeedToRebuild = false;
- haveRebuilt = true;
- return sfHookRebuildList;
- } else if (haveRebuilt) {
- haveRebuilt = false;
- EnsureSelection(myData->whichFocused);
- } else if (onceThrough && needToFixButtons) {
- if (!tabKludge) {
- FixButtons(theDialogP, ioParam);
- needToFixButtons = false;
- } else if (myData->whichFocused == kUserItem_FileList)
- tabKludge = false; // for some reason, it seems to take an extra cycle
- // to update the Reply field after tabbing to the Toolbox List
- }
- break;
- default:
- break;
- }
- return item;
- }
- // --------------------------------------------------------------------------------------------
- // EnsureSelection
- // --------------------------------------------------------------------------------------------
- void UGetMultipleFiles::EnsureSelection(short inActiveList)
- {
- ListHandle activeListH = (inActiveList == kUserItem_FileList) ? gToolboxList : sAddedListH;
- Cell theCell = {0, 0};
- if (!LGetSelect(true, &theCell, activeListH))
- LSetSelect(true, theCell, activeListH);
- }
-
- // --------------------------------------------------------------------------------------------
- // MyDrawListItem
- // This routine was taken from the Apple Macintosh Developer Technical Support
- // Standard File Application, which I downloaded from Apple's web site, and modified.
- // --------------------------------------------------------------------------------------------
- pascal void UGetMultipleFiles::MyDrawListItem (WindowPtr theWindow, short item)
- {
- Rect itemRect;
- Handle itemHandle;
- PenState myPenState; // current status of pen
-
- if (item == kUserItem_AddedList) {
- LUpdate((*theWindow).visRgn, sAddedListH);
- GetPenState(&myPenState); // store pen state
- GetDialogItem((DialogPtr) theWindow, item, userItem, &itemHandle, &itemRect);
- PenSize(1, 1); // set pen to 1 pixel
- InsetRect(&itemRect, -1, -1); // adjust rectangle for framing
- FrameRect(&itemRect); // draw border
- SetPenState(&myPenState); // restore old pen state
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // MyCreateTextListInDialog
- // This routine was taken from Inside Macintosh:More Macintosh Toolbox,
- // List Manager chapter.
- // --------------------------------------------------------------------------------------------
- ListHandle UGetMultipleFiles::MyCreateTextListInDialog (DialogPtr myDialog, short myItemNumber)
- {
- const short kTextLDEF = 0; // resource ID of default LDEF
-
- Rect myUserItemRect; // enclosure of user item
- Handle myUserItemHdl; // for GetDialogItem
-
- GetDialogItem(myDialog, myItemNumber, userItem,
- &myUserItemHdl, &myUserItemRect);
- return MyCreateVerticallyScrollingList(myDialog, myUserItemRect,
- 1, kTextLDEF);
- }
-
- // --------------------------------------------------------------------------------------------
- // MyCreateVerticallyScrollingList
- // This routine was taken from Inside Macintosh:More Macintosh Toolbox,
- // List Manager chapter.
- // --------------------------------------------------------------------------------------------
- ListHandle UGetMultipleFiles::MyCreateVerticallyScrollingList (WindowPtr myWindow, Rect myRect,
- short columnsInList, short myLDEF)
- {
- const short kDoDraw = TRUE; // always draw list after changes
- const short kNoGrow = FALSE; // don't leave room for size box
- const short kIncludeScrollBar = TRUE; // leave room for scroll bar
- const short kScrollBarWidth = 15; // width of vertical scroll bar
-
- Rect myDataBounds; // initial dimensions of the list
- Point myCellSize; // size of each cell in list
-
- // specify dimensions of the list
- // start with a list that contains no rows
- SetRect(&myDataBounds, 0, 0, columnsInList, 0);
-
- // let the List Manager calculate the size of a cell
- SetPt(&myCellSize, 0, 0);
-
- // adjust the rectangle to leave room for the scroll bar
- myRect.right = myRect.right - kScrollBarWidth;
-
- // create the list
- return LNew(&myRect, &myDataBounds, myCellSize, myLDEF, myWindow,
- kDoDraw, kNoGrow, !kIncludeScrollBar, kIncludeScrollBar);
- }
-
- // --------------------------------------------------------------------------------------------
- // AddOneToList - Add the currently selected file to the list. This can be done only because
- // the Standard File Package fills in the reply record before it calls the dialog hook
- // function (a point not well-documented in IM). We made the "Open" button our "Add"
- // button so that this would occur for us. (The dialog hook has extracted the fields
- // of the reply record for us already)
- // --------------------------------------------------------------------------------------------
- void UGetMultipleFiles::AddOneToList(Str255 name, long theDir, short theVRef)
- {
- Point theCell;
- FSSpec theFSSpec;
- ArrayIndexT foundAt; // the index in the FSSpec array of this file, if present already
- ArrayIndexT putAt; // where in the FSSpec array to put this file
- char theName[256];
-
- LString::CopyPStr((unsigned char *)name, (unsigned char *)theFSSpec.name);
- theFSSpec.parID = theDir;
- theFSSpec.vRefNum = theVRef;
- theCell.v = theCell.h = 0;
-
- // First, check to see if the file is already present in list
- foundAt = sTheFSpecs->FetchIndexOf(&theFSSpec);
- if (foundAt == sTheFSpecs->index_Bad) { // if it's not already present
- putAt = sTheFSpecs->FetchInsertIndexOf(&theFSSpec); // figure out where to put it, based on the FSSpec array
- sTheFSpecs->InsertItemsAt(1, putAt, &theFSSpec); // insert it into the FSSpec array
- // set the text of this new row to be the name of the file
- theCell.v = LAddRow (1, (short) putAt-1, sAddedListH); // insert a blank row into the displayed list for this file
- LString::CopyPStr((unsigned char *)theFSSpec.name, (unsigned char *)theName);
- if (!IsFile(theFSSpec)) { // it's a folder or a volume
- if (theFSSpec.parID != fsRtParID) // if it's a folder (not a volume)
- LString::AppendPStr((unsigned char *)theName, "\p:", 256);
- else {
- char temp[256];
- LString::CopyPStr("\p[", (unsigned char *)temp, 256);
- LString::AppendPStr((unsigned char *)temp, (unsigned char *)theName, 256);
- LString::AppendPStr((unsigned char *)temp, "\p]", 256);
- LString::CopyPStr((unsigned char *)temp, (unsigned char *)theName, 256);
- }
- }
- LSetCell (theName, sizeof(char) * (strlen(p2cstr((unsigned char *)theName))+1), theCell, sAddedListH);
- // set the text of this new row to be the name of the file
- }
- // set the button states
- theCell.v = theCell.h = 0;
- if ((sTheFSpecs->GetCount() != 0) && (LGetSelect(true, &theCell, sAddedListH))) {
- // list is not empty & something is selected, so enable Remove
- SetEnable(kStdButton_Remove, true); // enable remove button
- }
- if (sTheFSpecs->GetCount() != 0) {
- // list is not empty, so enable Remove All
- SetEnable(kStdButton_RemoveAll, true); // enable remove all button
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // RemoveFromList - Remove all files in the current selection from the list, leaving the
- // selection on the item just after the last one that was deleted, or at the end of the
- // remaining list if the bottom cell was selected and removed.
- // --------------------------------------------------------------------------------------------
- void UGetMultipleFiles::RemoveFromList()
- {
- Point theCell;
- short lastCell;
-
- theCell.v = theCell.h = 0;
- while (LGetSelect(true, &theCell, sAddedListH)) { // for each selected cell
- lastCell = theCell.v;
- (theCell.v)++;
- } // lastCell is now the cell number of the last selected cell in the list
- theCell.v = theCell.h = 0;
- while (LGetSelect(true, &theCell, sAddedListH)) { // for each selected cell
- sTheFSpecs->RemoveItemsAt(1, theCell.v + 1); // remove this item from the FSSpec array
- LDelRow(1, theCell.v, sAddedListH); // remove this item from the displayed list
- lastCell--;
- }
- if (sTheFSpecs->GetCount() == 0) { // list is empty, so disable Remove & Remove All
- SetEnable(kStdButton_Remove, false); // disable remove button
- SetEnable(kStdButton_RemoveAll, false); // disable remove all button
- } else { // set selection at the cell that was below the last one deleted, or
- // on the last one remaining in the list
- theCell.v = lastCell + 1;
- LSetSelect(true, theCell, sAddedListH);
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // AddAllToList - Add all items in the current directory to the list.
- // This has to be accomplished in a roundabout way, because we can't directly get a list
- // of the files showing in the SF list. So instead, we look at each file in the current
- // directory, check it against out typelist, and add it if it has a good type.
- // --------------------------------------------------------------------------------------------
- void UGetMultipleFiles::AddAllToList(Boolean atDesktop)
- {
- OSErr myErr = noErr;
- FSSpecPtr items = new FSSpec[kMaxNumFilesToFind];
- short maxToGet = kMaxNumFilesToFind;
- short numFound;
- short itemIndex = 1; // start at first entry in directory
- Boolean typeFound;
-
- while( myErr == noErr ) { // while there are files to get from the directory
- myErr = GetDirItems(GetSFVRefNum(),
- GetSFCurDir(),
- nil,
- true,
- true,
- items,
- maxToGet,
- &numFound,
- &itemIndex); // itemIndex returns pointing to the next
- // directory entry to be found, next time through
- switch (myErr) {
- case noErr: // This error code means 'repeat WHILE loop again, getting
- // the next batch of names'. This process will continue, adding ALL
- // names until whole directory has been traversed. Thus, we want to
- // perform the same task as the fnfErr condition, and then the WHILE
- // loop will repeat to get the next batch of names.
-
- case fnfErr: // this error means it worked.
- {
- for (short i=0; i<=numFound-1; i++) { // for each file, check it's type and add
- // it to the list if appropriate.
- FInfo theFinderInfo;
- FSSpec theFSpec;
- OSErr myErr;
-
- LString::CopyPStr((unsigned char *)(items[i]).name, (unsigned char *)theFSpec.name);
- theFSpec.parID = (items[i]).parID;
- theFSpec.vRefNum = (items[i]).vRefNum;
- myErr = FSpGetFInfo((const FSSpec *) &theFSpec, &theFinderInfo);
-
- typeFound = TypeInList( theFinderInfo.fdType );
-
- // if theFSSpec isn't in the exclusion list, or there is no list
- if (sNixFiles == nil || (sNixFiles->FetchIndexOf(&theFSpec) == sNixFiles->index_Bad)) {
- if ((typeFound) || (sNumTypes == -1)) {
- AddOneToList(theFSpec.name, theFSpec.parID, theFSpec.vRefNum);
- }
- }
- }
- }
- break;
- default:
- Throw_(err_otherGetDirErr);
- break;
- }
- } // end while myErr == noErr
- if (atDesktop) {
- // then find FSSpec for each volume (?) and add it to the list, if it's not already present
- HParamBlockRec pb;
- Str31 volName;
- FSSpec theVSpec; // we're going to pretend that we can treat a volume like a file
- short numVolume = 1;
- myErr = noErr;
- while (myErr == noErr) { // for each volume:
- pb.volumeParam.ioVolIndex = numVolume++;
- pb.volumeParam.ioNamePtr = volName;
- myErr = PBHGetVInfoSync(&pb);
- if (myErr == noErr) { // then add it to the list
- LString::CopyPStr((unsigned char *)volName, (unsigned char *)theVSpec.name);
- theVSpec.vRefNum = pb.volumeParam.ioVRefNum;
- theVSpec.parID = fsRtParID; // this is the parent ID of the root directory (a convenient fiction), and will serve to denote the whole volume
-
- // if theVSpec isn't in the exclusion list, or there is no list
- if (sNixFiles == nil || (sNixFiles->FetchIndexOf(&theVSpec) == sNixFiles->index_Bad)) {
- AddOneToList(theVSpec.name, theVSpec.parID, theVSpec.vRefNum);
- }
- }
- }
- if (myErr == nsvErr) { // this error means we got all the volumes!
- // do nothing - we're happy
- }
- }
- delete[] items;
- }
-
- // --------------------------------------------------------------------------------------------
- // RemoveAllFromList - Remove all files from our list.
- // --------------------------------------------------------------------------------------------
- void UGetMultipleFiles::RemoveAllFromList()
- {
- Point theCell;
-
- theCell.v = theCell.h = 0;
-
- while (sTheFSpecs->GetCount() != 0) { // as long as there's a cell left
- theCell.v = sTheFSpecs->GetCount() - 1; // pick the last cell
- sTheFSpecs->RemoveItemsAt(1, theCell.v + 1); // remove this thing from the FSSpec array
- LDelRow(1, theCell.v, sAddedListH); // remove it from the displayed list
- }
- if (sTheFSpecs->GetCount() == 0) { // list is empty, so disable Remove & Remove All
- SetEnable(kStdButton_Remove, false); // disable remove button
- SetEnable(kStdButton_RemoveAll, false); // disable remove all button
- } else { // set selection on the last one remaining in the list
- theCell.v = sTheFSpecs->GetCount() - 1; // (we should never be here)
- LSetSelect(true, theCell, sAddedListH);
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // Utility functions
- // --------------------------------------------------------------------------------------------
- long UGetMultipleFiles::GetSFCurDir(void)
- {
- return *((long *)0x398);
- }
-
- short UGetMultipleFiles::GetSFVRefNum(void)
- {
- return -1 * (*((short *)0x214));
- }
-
- void UGetMultipleFiles::SetCurrentVolume(short vRefNum)
- {
- (*((short *)0x214)) = -vRefNum;
- }
-
- void UGetMultipleFiles::SetCurrentDirectory(long dirID)
- {
- *((long *)0x398) = dirID;
- }
-
- void UGetMultipleFiles::SetEnable(ResIDT theItem, Boolean enabled)
- {
- Rect itemRect;
- Handle itemHandle;
-
- GetDialogItem(sDialogP, theItem, btnCtrl, &itemHandle, &itemRect);
-
- if (enabled)
- HiliteControl((ControlHandle)itemHandle, 0);
- else
- HiliteControl((ControlHandle)itemHandle, 255);
- }
-
-
- Boolean UGetMultipleFiles::GetEnabled(ResIDT theItem)
- {
- Rect itemRect;
- Handle itemHandle;
-
- GetDialogItem(sDialogP, theItem, btnCtrl, &itemHandle, &itemRect);
-
- return ((**((ControlHandle)itemHandle)).contrlHilite < kControlDisabledPart);
- }
-
- // --------------------------------------------------------------------------------------------
- // fixButtons - Sets enabled/disabled states, and default, based on selections & lists
- // --------------------------------------------------------------------------------------------
- void UGetMultipleFiles::FixButtons (DialogPtr theDialogP, void *ioParam)
- {
- static DialogPeek theDP = (DialogPeek) theDialogP;
- Boolean topEmpty = ((**gToolboxList).dataBounds.bottom == 0);
- Boolean botEmpty = (sTheFSpecs->GetCount() == 0);
- Rect itemRect;
- Handle itemHandle;
- RGBColor bgColor, fgSaveColor;
- PenState curPen;
- short dataSize = sizeof(Str63);
- Cell curSelCell = {0,0};
- Boolean toolboxActive = ((dataHolderType *)ioParam)->whichFocused == kUserItem_FileList;
-
- SetEnable(kStdButton_RemoveAll, !botEmpty); // enable remove all button if added list isn't empty
- SetEnable(kStdButton_Remove, !botEmpty && !toolboxActive); // enable remove button if added list is active and non-empty
- SetEnable(kStdButton_AddAll, !topEmpty); // enable add all if top list isn't empty
- if (sAddFolders)
- SetEnable(kStdButton_Select, (!topEmpty) && toolboxActive); // enable add all if top list is active and non-empty
- SetEnable(kStdButton_Add, (!topEmpty) && toolboxActive); // enable add all if top list is active and non-empty
-
- if ( sAddFolders && toolboxActive) {
- // set text for folder button:
- GetDialogItem(theDialogP, kStdButton_Select, btnCtrl, &itemHandle, &itemRect);
- if (topEmpty) { // if there are no entries in the top list
- ::SetControlTitle((ControlHandle) itemHandle, "\pNothing to Add");
- ::ValidRect(&itemRect);
- } else {
- SetButtonTitle(itemHandle, sReply.sfFile.name, itemRect);
- }
- }
- // if top list is empty, and bottom list isn't, then set default button to Done
- if (topEmpty && !botEmpty) {
- if (theDP->aDefItem != kStdButton_Done) {
- theDP->aDefItem = kStdButton_Done;
- GetDialogItem(theDialogP, kStdButton_Done, btnCtrl, &itemHandle, &itemRect);
- InsetRect(&itemRect, -4, -4);
- InvalRect(&itemRect);
- GetDialogItem(theDialogP, sfItemOpenButton, btnCtrl, &itemHandle, &itemRect);
- InsetRect(&itemRect, -4, -4);
- GetPenState(&curPen);
- PenSize(3, 3);
- GetBackColor(&bgColor);
- GetForeColor(&fgSaveColor);
- RGBForeColor(&bgColor);
- FrameRoundRect(&itemRect, 16, 16);
- RGBForeColor(&fgSaveColor);
- SetPenState(&curPen);
- }
- } else {
- if (theDP->aDefItem != sfItemOpenButton) {
- theDP->aDefItem = sfItemOpenButton;
- GetDialogItem(theDialogP, sfItemOpenButton, btnCtrl, &itemHandle, &itemRect);
- InsetRect(&itemRect, -4, -4);
- InvalRect(&itemRect);
- GetDialogItem(theDialogP, kStdButton_Done, btnCtrl, &itemHandle, &itemRect);
- InsetRect(&itemRect, -4, -4);
- GetPenState(&curPen);
- PenSize(3, 3);
- GetBackColor(&bgColor);
- GetForeColor(&fgSaveColor);
- RGBForeColor(&bgColor);
- FrameRoundRect(&itemRect, 16, 16);
- RGBForeColor(&fgSaveColor);
- SetPenState(&curPen);
- }
- }
- }
-
- // Utility by TE
-
- Boolean UGetMultipleFiles::TypeInList( OSType inType )
- {
- if( sNumTypes == -1 )
- return true;
-
- for (short j=0; j <= sNumTypes; j++)
- { // for each type in the list:
- if (inType == sTypeList[j]) // is this file's type one in the list?
- return true;
- }
- return false;
- }
-
- // Taken from IM:Files pg 3-35
- void UGetMultipleFiles::SetButtonTitle (Handle ButtonHdl, Str255 name, Rect ButtonRect)
- {
- short result, width;
- LStr255 finalStr;
-
- width = (ButtonRect.right - ButtonRect.left) - (StringWidth(kFolderButtonRoot) + CharWidth(' '));
- result = TruncString(width, name, smTruncMiddle);
- finalStr = kFolderButtonRoot;
- finalStr.Append(name);
- finalStr.Append('"');
- ::SetControlTitle((ControlHandle) ButtonHdl, finalStr);
- ::ValidRect(&ButtonRect);
- }
-
- void UGetMultipleFiles::ReplaceString ( Str255 destStr, Str255 whatStr, Str255 byStr )
- {
- Handle tH;
- long newOffset;
- short len;
-
- tH = NewHandle(512L);
- BlockMove((Ptr) destStr, *tH, destStr[0]+1);
- newOffset = Munger(tH, 0L, &whatStr[1], whatStr[0], &byStr[1], byStr[0]);
- if (newOffset > 0) {
- len = destStr[0];
- BlockMove(*tH, (Ptr) destStr, 255);
- len = len + byStr[0] - whatStr[0];
- if (len > 255)
- len = 255;
- destStr[0] = len;
- }
- DisposeHandle(tH);
- }
-
- void UGetMultipleFiles::DoListKey(short theKey, ListHandle theListH)
- {
- Cell theCell = {0,0};
- short numVisible = (**theListH).visible.bottom - (**theListH).visible.top;
-
- switch (theKey) {
- case kHome:
- if (LGetSelect(true, &theCell, theListH)) {
- LSetSelect(false, theCell, theListH);
- theCell.v = 0;
- LSetSelect(true, theCell, theListH);
- LAutoScroll(theListH);
- }
- break;
- case kEnd:
- if (LGetSelect(true, &theCell, theListH)) {
- LSetSelect(false, theCell, theListH);
- theCell.v = (**theListH).dataBounds.bottom-1;
- LSetSelect(true, theCell, theListH);
- LAutoScroll(theListH);
- }
- break;
- case kUpArrow:
- if (theListH != gToolboxList) {
- if (LGetSelect(true, &theCell, theListH)) {
- LSetSelect(false, theCell, theListH);
- if (theCell.v > 0)
- (theCell.v)--;
- LSetSelect(true, theCell, theListH);
- LAutoScroll(theListH);
- }
- }
- break;
- case kDownArrow:
- if (theListH != gToolboxList) {
- if (LGetSelect(true, &theCell, theListH)) {
- LSetSelect(false, theCell, theListH);
- if (theCell.v < (**theListH).dataBounds.bottom-1)
- (theCell.v)++;
- LSetSelect(true, theCell, theListH);
- LAutoScroll(theListH);
- }
- }
- break;
- case kPageUp:
- if (LGetSelect(true, &theCell, theListH)) {
- LSetSelect(false, theCell, theListH);
- if (theCell.v > numVisible-1)
- theCell.v -= numVisible;
- else
- theCell.v = 0;
- LSetSelect(true, theCell, theListH);
- LAutoScroll(theListH);
- }
- break;
- case kPageDown:
- if (LGetSelect(true, &theCell, theListH)) {
- LSetSelect(false, theCell, theListH);
- if (theCell.v < (**theListH).dataBounds.bottom - numVisible)
- theCell.v += numVisible;
- else
- theCell.v = (**theListH).dataBounds.bottom-1;
- LSetSelect(true, theCell, theListH);
- LAutoScroll(theListH);
- }
- break;
- }
- if (theListH == gToolboxList)
- needToFixButtons = true;
- }
-
- Boolean UGetMultipleFiles::IsFile(FSSpec inFile)
- {
- CInfoPBRec pb;
- OSErr error;
-
- error = GetCatInfoNoName(inFile.vRefNum, inFile.parID, inFile.name, &pb);
- if ( error == noErr )
- if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
- return false;
- return true;
- //handle error in GetCatInfoNoName here FIX
- }
-
- // --------------------------------------------------------------------------------------------
- // GetCatInfoNoName - Taken from MoreFiles 1.4.5
- // --------------------------------------------------------------------------------------------
- OSErr UGetMultipleFiles::GetCatInfoNoName(short vRefNum,
- long dirID,
- ConstStr255Param name,
- CInfoPBPtr pb)
- {
- Str31 tempName;
- OSErr error;
-
- /* Protection against File Sharing problem */
- if ( (name == NULL) || (name[0] == 0) )
- {
- tempName[0] = 0;
- pb->dirInfo.ioNamePtr = tempName;
- pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- else
- {
- pb->dirInfo.ioNamePtr = (StringPtr)name;
- pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- pb->dirInfo.ioVRefNum = vRefNum;
- pb->dirInfo.ioDrDirID = dirID;
- error = PBGetCatInfoSync(pb);
- pb->dirInfo.ioNamePtr = NULL;
- return ( error );
- }
-