eudora-mac/fileview.c

1 line
27 KiB
C
Executable File

/* Copyright (c) 2017, Computer History Museum
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
the limitations in the disclaimer below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. */
void FVSizeDispose(FileViewHandle fvh);
#include "fileview.h"
#define FILE_NUM 58
#define kHeaderButtonHeight (GROW_SIZE+5)
#define kCheckSeconds 5 // How often to check for upates to folder?
#define kFVButtonRef 'fvew'
typedef struct
{
Str32 name;
VLNodeID nodeID;
Boolean folder;
uLong size;
uLong date;
} FVFileInfo;
long FileViewLVCallBack(ViewListPtr pView, VLCallbackMessage message, long data);
static Boolean FileViewDrawRow(ViewListPtr pView,short item,Rect *pRect,CellRec *pCellData,Boolean select,Boolean eraseName);
static Boolean FileViewFillBlank(ViewListPtr pView);
static Boolean FileViewGetCellRects(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Rect *iconRect, Rect *nameRect);
static Boolean FileViewInterestingClick(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Point pt);
static void FileViewGetRects(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Rect *iconRect, Rect *nameRect, Point *ptName);
static void DrawListColors(FileViewHandle fvh, Rect *pRect, Boolean separator);
static void FVAddFiles(ViewListPtr pView,FileViewHandle fvh,long dirId);
void DrawFitting(StringPtr s, short width);
void SetColButton(FileViewHandle fvh);
static void FVSwapFiles(FVFileInfo *f1,FVFileInfo *f2);
static int FVCompareName(FVFileInfo *f1,FVFileInfo *f2);
static int FVCompareSize(FVFileInfo *f1,FVFileInfo *f2);
static int FVCompareDate(FVFileInfo *f1,FVFileInfo *f2);
short colLeft[kFDColCount+1] = { 0,250,395,457 };
short gCntlId[kFDColCount] = { FV_NAME_CNTL,FV_DATE_CNTL,FV_SIZE_CNTL };
/************************************************************************
* NewFileView - create a new file view
************************************************************************/
void NewFileView(MyWindowPtr win, FileViewHandle hData)
{
ViewListPtr pList;
WindowPtr winPtr = GetMyWindowWindowPtr(win);
if (pList=NuPtr(sizeof(ViewList)))
{
Rect rList;
DrawDetailsStruct details;
short i;
(*hData)->list = pList;
GetPortBounds(GetMyWindowCGrafPtr(win),&rList);
rList.top = win->topMargin;
LVInitDetails(&details);
details.DrawRowCallback = FileViewDrawRow;
details.FillBlankCallback = FileViewFillBlank;
// details.GetCellRectsCallBack = FileViewGetCellRects;
// details.InterestingClickCallback = FileViewInterestingClick;
LVNewWithDetails(pList,win,&rList,(*hData)->dirId,FileViewLVCallBack,kLVDoOwnDragAdd,&details);
for (i = 0;i < kFDColCount;i++)
{
ControlRef cntl = NewIconButton(gCntlId[i],winPtr);
if (cntl && win->topMarginCntl) EmbedControl(cntl,win->topMarginCntl);
SetControlReference(cntl,kFVButtonRef+i);
switch (i)
{
case kNameCol:
SetBevelTextOffset(cntl,details.iconLevelWidth*2);
break;
case kSizeCol:
SetBevelTextAlign(cntl,kControlBevelButtonAlignTextFlushRight);
case kDateCol:
SetBevelTextOffset(cntl,5);
break;
}
(*hData)->controls[i] = cntl;
}
SetColButton(hData);
}
}
/************************************************************************
* FVDispose - dispose of file view
************************************************************************/
void FVDispose(FileViewHandle fvh)
{
ZapHandle((*fvh)->expandList.hExpandList);
LVDispose((*fvh)->list);
ZapPtr((*fvh)->list);
}
/************************************************************************
* FVRemoveButtons - get rid of buttons added to window
************************************************************************/
void FVRemoveButtons(MyWindowPtr win)
{
short i;
ControlRef cntl;
for (i = 0;i < kFDColCount;i++)
{
cntl = FindControlByRefCon(win,kFVButtonRef+i);
if (cntl)
DisposeControl(cntl);
else
return;
}
}
/************************************************************************
* FileViewLVCallBack - callback function for List View
************************************************************************/
long FileViewLVCallBack(ViewListPtr pView, VLCallbackMessage message, long data)
{
OSErr err = noErr;
FileViewHandle fvh = GetFileViewInfo(pView->wPtr);
CInfoPBRec hfi;
VLNodeInfo *pInfo, lvInfo, folderData;
FSSpec spec,toSpec;
short i;
short vRefNum = fvh?(*fvh)->vRefNum:0;
Boolean fMovedFolder,reDo=false;
SendDragDataInfo *pSendData;
HFSFlavor hfsInfo;
switch (message)
{
case kLVAddNodeItems:
FVAddFiles(pView,fvh,data);
break;
case kLVExpandCollapseItem:
pInfo = (VLNodeInfo*)data;
pInfo->refCon = pInfo->nodeID;
LDRef(fvh);
SaveExpandStatus(pInfo,&(*fvh)->expandList);
UL(fvh);
break;
case kLVGetParentID:
hfi.dirInfo.ioDrDirID = ((VLNodeInfo *)data)->nodeID;
hfi.dirInfo.ioNamePtr = lvInfo.name;
hfi.dirInfo.ioVRefNum = vRefNum;
hfi.dirInfo.ioFDirIndex = -1; /* use ioDirID */
if (PBGetCatInfo(&hfi,0)) /* get working directory info */
return nil;
return hfi.dirInfo.ioDrDirID;
break;
case kLVMoveItem:
case kLVCopyItem:
pInfo = (VLNodeInfo*)data;
FSMakeFSSpec(vRefNum,pInfo->nodeID,"",&toSpec);
IsAlias(&toSpec,&toSpec);
if (toSpec.vRefNum != vRefNum)
{
// aliased to another volume, no can do
WarnUser(CANT_VOL_MOVE,0);
return 0;
}
fMovedFolder = false;
// fall thru
case kLVDeleteItem:
if (data == dataDeleteFromDrag) break; // Don't handle drag to trash here
case kLVOpenItem:
for (i=1;i<=LVCountSelection(pView);i++)
{
LVGetItem(pView,i,&lvInfo,true);
FSMakeFSSpec(vRefNum,lvInfo.nodeID,lvInfo.isParent?"":lvInfo.name,&spec);
switch (message)
{
case kLVOpenItem:
OpenOtherDoc(&spec,false,false,nil);
break;
case kLVDeleteItem:
FSpTrash(&spec);
reDo = true;
break;
case kLVMoveItem:
case kLVCopyItem:
if (fMovedFolder && LVDescendant(pView,&lvInfo,&folderData))
// We have already moved an ancestor of this file. Don't
// try to move it again
continue;
if (fMovedFolder = lvInfo.isParent)
// Moved a folder
folderData = lvInfo;
if (LVDescendant(pView,&lvInfo,pInfo)==1)
// Don't try to move a child into its parent--it's already there
continue;
if (message==kLVMoveItem)
err = FSpCatMove(&spec,&toSpec);
else
{
toSpec.parID = SpecDirId(&toSpec);
PCopy(toSpec.name,spec.name);
if (lvInfo.isParent)
{
uLong createdDirID;
spec.parID = SpecDirId(&spec);
if (!(err = FSpDirCreate(&toSpec,smSystemScript,&createdDirID)))
{
toSpec.parID = createdDirID;
err = FSpDupFolder(&toSpec,&spec,false,false);
}
}
else
err = FSpDupFile(&toSpec,&spec,false,false);
}
reDo = true;
break;
}
}
break;
case kLVRenameItem:
{
Str31 newName;
SanitizeFN(newName,(StringPtr)data,MAC_FN_BAD,MAC_FN_REP,false);
LVGetItem(pView,1,&lvInfo,true);
if (*newName && !EqualString(newName,lvInfo.name,true,true))
{
FSMakeFSSpec(vRefNum,lvInfo.nodeID,lvInfo.isParent?"":lvInfo.name,&spec);
FSpRename(&spec,newName);
reDo = true;
}
break;
}
case kLVQueryItem:
pInfo = (VLNodeInfo*)data;
switch (pInfo->query)
{
case kQuerySelect:
case kQueryDrag:
case kQueryRename:
case kQueryDropParent:
case kQueryDragExpand:
return true;
case kQueryDrop:
return pInfo->isParent;
case kQueryDCOpens:
return !pInfo->isParent;
default:
return false;
}
break;
case kLVSendDragData:
case kLVAddDragItem:
pSendData = (SendDragDataInfo*)data;
pInfo = pSendData->info;
FSMakeFSSpec(vRefNum,pInfo->nodeID,pInfo->isParent?"":pInfo->name,&hfsInfo.fileSpec);
if (pInfo->isParent)
{
hfsInfo.fileType = 'MACS';
hfsInfo.fileType = 'fold';
hfsInfo.fdFlags = 0;
}
else
{
FInfo fndrInfo;
FSpGetFInfo(&hfsInfo.fileSpec,&fndrInfo);
hfsInfo.fileType = fndrInfo.fdType;
hfsInfo.fileCreator = fndrInfo.fdCreator;
hfsInfo.fdFlags = fndrInfo.fdFlags;
}
AddDragItemFlavor(pSendData->drag,pSendData->itemRef,flavorTypeHFS,&hfsInfo,sizeof(hfsInfo),flavorNotSaved);
// Make sure we cause the list to be updated
(*fvh)->lastUpdateCheck = 0;
(*fvh)->lastUpdate = 0;
break;
case kLVDragDrop:
// Drop from external source
pSendData = (SendDragDataInfo*)data;
pInfo = pSendData->info;
if (pInfo->isParent)
{
short i,n;
short modifiers,mouseDownModifiers,mouseUpModifiers;
GetDragModifiers(pSendData->drag, &modifiers, &mouseDownModifiers, &mouseUpModifiers);
FSMakeFSSpec(vRefNum,pInfo->nodeID,"",&toSpec);
n = MyCountDragItems(pSendData->drag);
for (i=1;i<=n && !err; i++)
{
Handle data = nil;
if (!(err=MyGetDragItemData(pSendData->drag,i,flavorTypeHFS,&data)))
{
// File drag from Finder
spec = (*(struct HFSFlavor**)data)->fileSpec;
ZapHandle(data);
if ((modifiers|mouseDownModifiers|mouseUpModifiers)&optionKey)
{
// copy files
toSpec.parID = SpecDirId(&toSpec);
PCopy(toSpec.name,spec.name);
if (AFSpIsItAFolder(&spec))
{
uLong createdDirID;
spec.parID = SpecDirId(&spec);
if (!(err = FSpDirCreate(&toSpec,smSystemScript,&createdDirID)))
{
toSpec.parID = createdDirID;
err = FSpDupFolder(&toSpec,&spec,false,false);
}
}
else
err = FSpDupFile(&toSpec,&spec,false,false);
}
else
// move files
err = FSpCatMove(&spec,&toSpec);
reDo = true;
}
}
}
break;
case kLVGetFlags:
return kfDropRoot;
}
if (reDo) InvalidListView(pView);
return err;
}
/**********************************************************************
* FileViewUpdate - update the window in file view mode
**********************************************************************/
void FileViewUpdate(MyWindowPtr win)
{
FileViewHandle fvh = GetFileViewInfo(win);
if (fvh) LVDraw((*fvh)->list,MyGetPortVisibleRegion(GetMyWindowCGrafPtr(win)),true,false);
}
/**********************************************************************
* FileViewClick - handle a click in the file view
**********************************************************************/
void FileViewClick(MyWindowPtr win,EventRecord *event)
{
FileViewHandle fvh = GetFileViewInfo(win);
if (win->isActive)
{
if (!fvh || !LVClick((*fvh)->list,event))
{
Point pt = event->where;
SetPort_(GetMyWindowCGrafPtr(win));
GlobalToLocal(&pt);
HandleControl(pt,win);
}
}
else
SelectWindow_(GetMyWindowWindowPtr(win));
}
/************************************************************************
* FileViewCursor - change the cursor appropriately
************************************************************************/
void FileViewCursor(Point mouse)
{
MyWindowPtr win=GetWindowMyWindowPtr(FrontWindow_());
if (win && !PeteCursorList(win->pteList,mouse))
SetMyCursor(arrowCursor);
}
/**********************************************************************
* FileViewDragHandler - handle dragging in file view
**********************************************************************/
OSErr FileViewDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag)
{
OSErr err = noErr;
if (DragIsInteresting(drag,kDragFlavorTypeHFS,TOC_FLAVOR,nil))
{
FileViewHandle fvh = GetFileViewInfo(win);
err = LVDrag((*fvh)->list,which,drag);
}
return err;
}
/************************************************************************
* FileViewKey - handle keystrokes in file view
************************************************************************/
Boolean FileViewKey(MyWindowPtr win, EventRecord *event)
{
FileViewHandle fvh = GetFileViewInfo(win);
return LVKey((*fvh)->list,event);
}
/**********************************************************************
* FileViewFind - find in the window
**********************************************************************/
Boolean FileViewFind(MyWindowPtr win,PStr what)
{
FileViewHandle fvh = GetFileViewInfo(win);
return FindListView(win,(*fvh)->list,what);
}
/************************************************************************
* MBMenu - menu choice in the mailbox window
************************************************************************/
Boolean FileViewMenu(MyWindowPtr win, int menu, int item, short modifiers)
{
#pragma unused(modifiers)
FileViewHandle fvh = GetFileViewInfo(win);
switch (menu)
{
case FILE_MENU:
switch(item)
{
case FILE_OPENSEL_ITEM:
FileViewLVCallBack((*fvh)->list,kLVOpenItem,nil);
return(True);
}
break;
case EDIT_MENU:
switch(item)
{
case EDIT_SELECT_ITEM:
LVSelectAll((*fvh)->list);
return(true);
case EDIT_COPY_ITEM:
LVCopy((*fvh)->list);
return true;
}
break;
}
return(False);
}
/************************************************************************
* FileViewDrawRow - callback function for List View. Draw a row.
************************************************************************/
static Boolean FileViewDrawRow(ViewListPtr pView,short item,Rect *pRect,CellRec *pCellData,Boolean select,Boolean eraseName)
{
Boolean result = true;
Rect rIcon, rName;
Point ptName;
FileViewHandle fvh = GetFileViewInfo(pView->wPtr);
FSSpec spec;
static Boolean checkedIconServices, haveIconServices;
IconRef iconRef;
SInt16 theLabel;
CInfoPBRec hfi;
Str255 s;
Str31 s2;
SInt32 gestaltResult;
// Draw the list background color and seperator lines for this row
DrawListColors(fvh,pRect,true);
// Get file info
FSMakeFSSpec((*fvh)->vRefNum,pCellData->nodeID,pCellData->misc.fParent?"":pCellData->name,&spec);
FSpGetHFileInfo(&spec,&hfi);
// Get icon
if (!checkedIconServices)
haveIconServices = !Gestalt(gestaltIconUtilitiesAttr,&gestaltResult) && (gestaltResult&gestaltIconUtilitiesHasIconServices) && GetIconRefFromFile;
iconRef = nil;
if (haveIconServices) GetIconRefFromFile(&spec,&iconRef,&theLabel);
// Draw the contents of this item
TextFont(pView->font);
TextSize(pView->fontSize);
FileViewGetRects(pView,pCellData,pRect,&rIcon,&rName,&ptName);
// Plot the icon
if (iconRef)
{
PlotIconRef(&rIcon,atNone+atHorizontalCenter,select ? ttSelected : ttNone,0,iconRef);
ReleaseIconRef(iconRef);
}
else if (pCellData->iconID)
PlotIconID(&rIcon,atNone+atHorizontalCenter,select ? ttSelected : ttNone,pCellData->iconID);
// Draw the name
MoveTo(ptName.h,ptName.v);
DrawFitting(pCellData->name,colLeft[kNameCol+1]-ptName.h);
if (select)
{
// highlight name
Point penLoc;
GetPortPenLocation(GetQDGlobalsThePort(),&penLoc);
rName.right = penLoc.h+5;
InvertRect(&rName);
}
// Draw date, time
DateString(hfi.hFileInfo.ioFlMdDat,shortDate,s,nil);
TimeString(hfi.hFileInfo.ioFlMdDat,false,s2,nil);
PCat(s,"\p, ");
PCat(s,s2);
MoveTo(colLeft[kDateCol]+5,ptName.v);
DrawFitting(s,colLeft[kDateCol+1]-colLeft[kDateCol]-5);
// Draw size
if (pCellData->misc.fParent)
// folder
PCopy(s,"\p-");
else
{
// file
uLong fileSize = (hfi.hFileInfo.ioFlPyLen + hfi.hFileInfo.ioFlRPyLen) / 1024;
char cBytes = 'K';
if (fileSize >= 1024)
{
fileSize /= 1024;
cBytes = 'M';
}
NumToString(fileSize,s);
PCatC(s,' ');
PCatC(s,cBytes);
}
MoveTo(colLeft[kSizeCol+1]-5-StringWidth(s),ptName.v); // right-justify
DrawString(s);
// Set background color in case disclosure triangle needs to be drawn
//MJD if (PrefIsSet(PREF_USE_LIST_COLORS))
//MJD SetThemeBackground((*fvh)->prefs.sortCol?kThemeBrushListViewBackground:kThemeBrushListViewSortColumnBackground,RectDepth(pRect),true);
return (result);
}
/************************************************************************
* DrawFitting - draw string making sure it fits
************************************************************************/
void DrawFitting(StringPtr s, short width)
{
if (StringWidth(s)>width)
{
TextFace(condense);
if (StringWidth(s)>width)
TruncString(width,s,smTruncMiddle);
}
DrawString(s);
}
/************************************************************************
* FileViewFillBlank - callback function for List View. Fill unused
* parts of the list.
************************************************************************/
static Boolean FileViewFillBlank(ViewListPtr pView)
{
ListHandle hList=pView->hList;
Rect rErase;
GrafPtr savePort;
FileViewHandle fvh = GetFileViewInfo(pView->wPtr);
if ((*hList)->visible.bottom > (*hList)->dataBounds.bottom)
{
SAVE_STUFF;
SET_COLORS;
GetPort(&savePort);
SetPort(GetMyWindowCGrafPtr(pView->wPtr));
Cell1Rect(hList,(*hList)->dataBounds.bottom+1,&rErase);
rErase.bottom = pView->bounds.bottom;
DrawListColors(fvh,&rErase,false);
SetPort(savePort);
REST_STUFF;
}
return true;
}
/************************************************************************
* DrawListColors - draw list colors
************************************************************************/
static void DrawListColors(FileViewHandle fvh, Rect *pRect, Boolean separator)
{
Rect columnRect;
short depth;
if (UseListColors)
{
// draw sort column
SetRect(&columnRect,pRect->left+colLeft[(*fvh)->prefs.sortCol],pRect->top,pRect->left+colLeft[(*fvh)->prefs.sortCol+1],pRect->bottom-1);
depth = RectDepth(&columnRect);
SetThemeBackground(kThemeBrushListViewSortColumnBackground,depth,true);
EraseRect(&columnRect);
SetThemeBackground(kThemeBrushListViewBackground,depth,true);
if ((*fvh)->prefs.sortCol)
{
// draw before sort column
columnRect.left = 0;
columnRect.right = colLeft[(*fvh)->prefs.sortCol]-1;
EraseRect(&columnRect);
}
// draw after sort column
columnRect.left = colLeft[(*fvh)->prefs.sortCol+1]+1;
columnRect.right = pRect->right;
EraseRect(&columnRect);
// draw separator
SetThemeBackground(kThemeBrushListViewSeparator,depth,true);
SetRect(&columnRect,0,columnRect.bottom,pRect->right,columnRect.bottom+1);
EraseRect(&columnRect);
}
}
/************************************************************************
* FileViewGetRects - return true if this we should drag
************************************************************************/
static void FileViewGetRects(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Rect *iconRect, Rect *nameRect, Point *ptName)
{
short offset;
Point pt;
FontInfo fInfo;
SAVE_STUFF;
// Icon
offset = pView->details.iconLeft + cellData->misc.level*pView->details.iconLevelWidth;
if (cellData->iconID)
{
SetRect(iconRect,cellRect->left+offset,cellRect->top+pView->details.iconTop,cellRect->left+offset+16,cellRect->top+pView->details.iconTop+16);
offset += pView->details.iconLevelWidth;
}
else
SetRect(iconRect,0,0,0,0);
// Name
TextFont(pView->font);
TextSize(pView->fontSize);
TextFace(cellData->misc.style);
pt.h = cellRect->left + offset;
pt.v = cellRect->top+(*pView->hList)->cellSize.v-pView->details.textBottom;
*ptName = pt;
GetFontInfo(&fInfo);
SetRect(nameRect,pt.h,pt.v-fInfo.ascent-fInfo.leading,cellRect->right,pt.v+fInfo.descent);
REST_STUFF;
}
/************************************************************************
* FileViewGetCellRects - return true if this we should drag
************************************************************************/
static Boolean FileViewGetCellRects(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Rect *iconRect, Rect *nameRect)
{
Point ptName;
FileViewGetRects(pView,cellData,cellRect,iconRect,nameRect,&ptName);
return (true);
}
/************************************************************************
* FileViewInterestingClick - return true if this point is interesting
************************************************************************/
static Boolean FileViewInterestingClick(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Point pt)
{
Boolean result = false;
Rect rIcon, rName;
FileViewGetCellRects(pView,cellData,cellRect,&rIcon,&rName);
if (PtInRect(pt,&rIcon) || PtInRect(pt,&rName)) result = true;
return (result);
}
/**********************************************************************
* GetFileViewInfo - get file view info from tab control
**********************************************************************/
FileViewHandle GetFileViewInfo(MyWindowPtr win)
{
TOCHandle tocH = (TOCHandle)GetMyWindowPrivateData(win);
return tocH ? (FileViewHandle)(*tocH)->hFileView : nil;
}
/**********************************************************************
* SetColButton - set correct header button for current sort
**********************************************************************/
void SetColButton(FileViewHandle fvh)
{
short i;
for(i = 0;i < kFDColCount;i++)
SetControlValue((*fvh)->controls[i],i==(*fvh)->prefs.sortCol?1:0);
}
/**********************************************************************
* FVSizeHeaderButtons - size and position header buttons
**********************************************************************/
void FVSizeHeaderButtons(MyWindowPtr win, FileViewHandle fvh)
{
short i;
for(i = 0;i < kFDColCount;i++)
MoveMyCntl((*fvh)->controls[i],colLeft[i],win->topMargin-kHeaderButtonHeight,colLeft[i+1]-colLeft[i],kHeaderButtonHeight);
}
/************************************************************************
* FileViewButton - handle a hit in a control
************************************************************************/
void FileViewButton(MyWindowPtr win,ControlHandle cntl,long modifiers,short part)
{
FileViewHandle fvh = GetFileViewInfo(win);
short i;
for(i = 0;i < kFDColCount;i++)
if ((*fvh)->controls[i] == cntl)
{
if ((*fvh)->prefs.sortCol != i)
{
(*fvh)->prefs.sortCol = i;
(*fvh)->dirtyPrefs = true;
SetColButton(fvh);
InvalidListView((*fvh)->list);
}
break;
}
}
/************************************************************************
* FVAddFiles - add files to list view
************************************************************************/
static void FVAddFiles(ViewListPtr pView,FileViewHandle fvh,long dirId)
{
VLNodeInfo lvInfo;
CInfoPBRec hfi;
Accumulator a;
FVFileInfo fileInfo,*pInfo;
void *compare;
short count=0,i;
if (AccuInit(&a)) return;
Zero(lvInfo);
hfi.hFileInfo.ioNamePtr = fileInfo.name;
hfi.hFileInfo.ioFDirIndex = 0;
while (!DirIterate((*fvh)->vRefNum,dirId,&hfi))
if (!(hfi.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible))
{
if ((hfi.hFileInfo.ioFlAttrib & ioDirMask))
{
// folder
fileInfo.folder = true;
fileInfo.nodeID = hfi.dirInfo.ioDrDirID;
fileInfo.size = 0;
}
else
{
// file
fileInfo.folder = false;
fileInfo.nodeID = dirId;
fileInfo.size = hfi.hFileInfo.ioFlPyLen + hfi.hFileInfo.ioFlRPyLen;
}
fileInfo.date = hfi.hFileInfo.ioFlMdDat;
AccuAddPtr(&a,&fileInfo,sizeof(fileInfo));
count++;
}
// Sort
switch ((*fvh)->prefs.sortCol)
{
case kDateCol: compare = FVCompareDate; break;
case kSizeCol: compare = FVCompareSize; break;
default: compare = FVCompareName; break;
}
QuickSort((void*)LDRef(a.data),sizeof(fileInfo),0,count-1,compare,(void*)FVSwapFiles);
// Put in list
for(i=0,pInfo=LDRef(a.data);i<count;i++,pInfo++)
{
PCopy(lvInfo.name,pInfo->name);
lvInfo.nodeID = pInfo->nodeID;
if (pInfo->folder)
{
// folder
lvInfo.iconID = kGenericFolderIconResource;
lvInfo.isParent = true;
LDRef(fvh);
lvInfo.isCollapsed = !FindExpandDirID(lvInfo.nodeID,&(*fvh)->expandList);
UL(fvh);
}
else
{
// file
lvInfo.iconID = kGenericDocumentIconResource;
lvInfo.isParent = false;
}
LVAdd(pView,&lvInfo);
}
if (dirId == (*fvh)->dirId)
{
Zero(hfi);
hfi.dirInfo.ioDrDirID = dirId;
hfi.dirInfo.ioVRefNum = (*fvh)->vRefNum;
hfi.dirInfo.ioFDirIndex = -1; /* use ioDirID */
PBGetCatInfo(&hfi,0);
(*fvh)->lastUpdate = hfi.dirInfo.ioDrMdDat;
(*fvh)->lastUpdateCheck = TickCount();
}
}
/************************************************************************
* FVSwapFiles - used for QuickSort
************************************************************************/
static void FVSwapFiles(FVFileInfo *f1,FVFileInfo *f2)
{
FVFileInfo t;
t = *f1;
*f1 = *f2;
*f2 = t;
}
/************************************************************************
* FVCompareName - used for QuickSort
************************************************************************/
static int FVCompareName(FVFileInfo *f1,FVFileInfo *f2)
{
return StringComp(f1->name,f2->name);
}
/************************************************************************
* FVCompareSize - used for QuickSort
************************************************************************/
static int FVCompareSize(FVFileInfo *f1,FVFileInfo *f2)
{
return (f1->size-f2->size);
}
/************************************************************************
* FVCompareDate - used for QuickSort
************************************************************************/
static int FVCompareDate(FVFileInfo *f1,FVFileInfo *f2)
{
return (f1->date-f2->date);
}
/**********************************************************************
* FileViewActivate - activate/deactivate
**********************************************************************/
void FileViewActivate(MyWindowPtr win)
{
FileViewHandle fvh = GetFileViewInfo(win);
LVActivate((*fvh)->list, win->isActive);
}
/************************************************************************
* FileViewIdle - idle routine for file view
************************************************************************/
void FileViewIdle(MyWindowPtr win)
{
FileViewHandle fvh = GetFileViewInfo(win);
// See if there have been any changes to the folder since the list
// time we got the files
if (fvh && TickCount() > (*fvh)->lastUpdateCheck+(kCheckSeconds*60))
{
CInfoPBRec hfi;
Zero(hfi);
hfi.dirInfo.ioDrDirID = (*fvh)->dirId;
hfi.dirInfo.ioVRefNum = (*fvh)->vRefNum;
hfi.dirInfo.ioFDirIndex = -1; /* use ioDirID */
PBGetCatInfo(&hfi,0);
if (hfi.dirInfo.ioDrMdDat > (*fvh)->lastUpdate)
// It's been changed. Update it.
InvalidListView((*fvh)->list);
}
}