/*********************************************************************** * * Copyright (c) 2006 Palm, Inc. or its subsidiaries. * All rights reserved. * ***********************************************************************/ /** @ingroup MiniImage * **/ /** @file FileBrowserForm.c * This file contains file browser functions for MiniImage **/ /** @name * **/ /*@{*/ /*********************************************************************** * * File: * FileBrowserForm.c * * Description: * File browsing form * * ***********************************************************************/ #include #include #include #include #include #include #include "Common.h" #include "FileBrowserForm.h" #include "FileBrowserFormRsrc.h" /*********************************************************************** * * Internal Defines * ***********************************************************************/ #define dataBaseType 'temp' #define dbCardNumber 0 /*********************************************************************** * * Internal typedef * ***********************************************************************/ typedef struct { Boolean selected; UInt16 attribute; UInt32 fileSize; Char* fileName; } FileBrowserFileInfo; /*********************************************************************** * * Internal functions * ***********************************************************************/ static Err PrvFormInit(FormType* frmP); static void PrvFormDeInit(); Err PrvEnumerate(); static Err PrvEmptyDB(); static Err PrvAddRecord(FileInfoType* fileInfoP, UInt32 fileSize); static Err PrvGetRecord(UInt16 index, FileBrowserFileInfo* fileInfoP, MemHandle* hP); static void PrvReleaseRecord(UInt16 index, MemHandle h); static void PrvDBSort(); static void PrvListViewInit(FormType* frmP); static void PrvListViewDrawFile(void* tableP, Int16 row, Int16 column, RectangleType* boundsP); static void PrvListViewLoadTable(FormType* frmP, Boolean redraw); static void PrvDrawTableBorder(FormType* frmP); static void PrvSelectFile(UInt16 index); void FileBrowserTestScrolling(TablePtr tableP); /*********************************************************************** * * Internal Globals * ***********************************************************************/ static DmOpenRef gDB = NULL; // Global pointer to the database static UInt16 gRowCount = 0; // Number of row in table/list view static UInt16 gTopIndex = 0; // Top index item of the table static UInt32 gFileCount = 0; // Number of files in database static UInt16 gVolumeCount = 0; // Number of cards static UInt16 gCurrentVolume = 0; static Char gCurrentPath[MAX_PATH_LENGTH] = { NULL }; static Char gCurrentFile[MAX_FILENAME_LENGTH] = { NULL }; static WinHandle gDocumentWinH = 0; // Document Bitmap buffer static WinHandle gFolderWinH = 0; // Folder Bitmap buffer static UInt32 gReturnForm = 0; // Form to return to static FileBrowserCallback gCallback = NULL; // Callback //static FileBrowserView gViewType = DIRECTORY | FILE; // Show files and folders //static FileBrowserSelection gSelectionType = SINGLE; // Single selection Int8 selectedRow; //flag to keep track of when scrolling has been used Boolean gScrolling = false; //flag to keep track of when the 5-way has been used //this flag is true when 5-way is used but need not be set to false Boolean gUsedUpDown = false; #pragma mark ---------- File Browser Functions ---------- /*********************************************************************** * * FUNCTION: FileBrowserFormHandleEvent * * DESCRIPTION: This routine handles the events for the File Browser Form * * PARAMETERS: eventP - The pointer to the event. * * RETURNED: True if handled. * ***********************************************************************/ Boolean FileBrowserFormHandleEvent(EventType * eventP) { TablePtr tableP; Boolean handled = false; FormType * frmP = FrmGetActiveForm(); switch (eventP->eType) { case keyDownEvent: switch( eventP->data.keyDown.chr) { case vchrRockerUp: case vchrPageUp: { tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); /* to get 5-way to sync with scrolling */ FileBrowserTestScrolling(tableP); //after we sync 5-way with scrolling, we can set the flag to false gScrolling = false; // Check that the selected row is within bounds and adjust focus to the selected row // Table is highlighted, we're not at the top of list if( selectedRow != -1 && selectedRow != 0) { // Scroll up if(selectedRow == gTopIndex) { gTopIndex--; selectedRow--; PrvListViewLoadTable(frmP, true); TblUnhighlightSelection(tableP); TblRedrawTable(tableP); } else { // No scrolling selectedRow--; } TblSelectItem (tableP, selectedRow - gTopIndex, 0); } // set flag to show that 5-way has been used gUsedUpDown = true; handled = true; break; } case vchrRockerDown: case vchrPageDown: { tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); /* to get 5-way to sync with scrolling */ FileBrowserTestScrolling(tableP); //after we sync 5-way with scrolling, we can set the flag to false gScrolling = false; // Check that the selected row is within bounds and adjust focus to the selected row // Table is highlighted and we're not at the bottom of list if(selectedRow != -1 && selectedRow != (gFileCount - 1)) { if(selectedRow < (gTopIndex + gRowCount - 1)) { // No scrolling selectedRow++; TblSelectItem (tableP, selectedRow - gTopIndex, 0); } else { // Scroll gTopIndex++; selectedRow++; TblUnhighlightSelection(tableP); TblRedrawTable(tableP); PrvListViewLoadTable(frmP, true); TblSelectItem (tableP, selectedRow - gTopIndex, 0); } } // set flag to show that 5-way has been used gUsedUpDown = true; handled = true; break; } case vchrRockerRight: { // Table is highlighted. Set focus on cancel button if( selectedRow != -1 ) { tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); TblUnhighlightSelection(tableP); FrmSetFocus(frmP, FrmGetObjectIndex(frmP, FileBrowserCancelButton)); PrvFormInit(frmP); FrmDrawForm(frmP); PrvDrawTableBorder(frmP); selectedRow = -1; } handled = true; break; } case vchrRockerLeft: { // Cancel button is highlighted. Set focus on table if(selectedRow == -1) { selectedRow = 0; gTopIndex = 0; tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); PrvFormDeInit(frmP); PrvFormInit(frmP); FrmDrawForm(frmP); PrvDrawTableBorder(frmP); FrmNavObjectTakeFocus(frmP, FileBrowserFileTable); TblSelectItem (tableP, selectedRow, 0); } handled = true; break; } case vchrHardRockerCenter: case vchrRockerCenter: tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); /* to get 5-way to sync with scrolling */ FileBrowserTestScrolling(tableP); // Table is highlighted. Select file/folder if(selectedRow != -1) { selectedRow = selectedRow - gTopIndex; gTopIndex = 0; PrvSelectFile(TblGetRowID(tableP, selectedRow)); selectedRow = 0; TblSelectItem (tableP, selectedRow, 0); // Cancel button is highlighted. Go back to main form } else { gTopIndex = 0; PrvListViewLoadTable(frmP, true); FrmGotoForm(gReturnForm); } //after we sync 5-way with scrolling and select our file, we can set the flag to false gScrolling = false; handled = true; break; } handled = true; break; case frmOpenEvent: PrvFormInit(frmP); FrmDrawForm(frmP); PrvDrawTableBorder(frmP); FrmNavObjectTakeFocus(frmP, FileBrowserFileTable); tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); TblSelectItem (tableP, selectedRow, 0); // Restore the insertion point position. handled = true; break; case ctlSelectEvent: switch(eventP->data.ctlSelect.controlID) { case FileBrowserCancelButton: FrmGotoForm(gReturnForm); handled = true; break; } break; case sclRepeatEvent: { tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); gTopIndex += (eventP->data.sclRepeat.newValue - eventP->data.sclRepeat.value); PrvListViewLoadTable(frmP, true); TblUnhighlightSelection(tableP); TblRedrawTable(tableP); TblSelectItem (tableP, 0, 0); //Show that scrolling has been used gScrolling = true; handled = false; break; } case frmUpdateEvent: PrvDrawTableBorder(frmP); break; case frmCloseEvent: PrvFormDeInit(); selectedRow = 0; gTopIndex = 0; handled = false; break; case tblEnterEvent: break; case tblSelectEvent: if( gFileCount > eventP->data.tblSelect.row ) { gTopIndex = 0; PrvSelectFile(TblGetRowID(eventP->data.tblSelect.pTable, eventP->data.tblSelect.row)); //after we select our file, we can set the scrolling flag to false gScrolling = false; handled = true; } break; default: break; } return handled; } /*********************************************************************** * * FUNCTION: FileBrowserTestScrolling * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ void FileBrowserTestScrolling(TablePtr tableP) { /* If scrolling has been used, the focus is moved to the top item in the frame */ if (gScrolling == true) { selectedRow = gTopIndex; TblSelectItem (tableP, selectedRow, 0); } } /*********************************************************************** * * FUNCTION: FileBrowserSetCallback * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ void FileBrowserSetCallback(FileBrowserCallback callback, UInt32 formID) { gCallback = callback; gReturnForm = formID; } /*********************************************************************** * * FUNCTION: FileBrowserIsCallbackSet * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ Boolean FileBrowserIsCallbackSet() { return (gCallback)?true:false; } /*********************************************************************** * * FUNCTION: FileBrowserIsReturnFormSet * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ Boolean FileBrowserIsReturnFormSet() { return (gReturnForm)?true:false; } /*********************************************************************** * * FUNCTION: FileBrowserRefresh * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ void FileBrowserRefresh() { FormType *frmP = FrmGetActiveForm(); // Empty the current database PrvEmptyDB(); // Load new files gRowCount = 0; gTopIndex = 0; gFileCount = 0; gVolumeCount = 0; gCurrentVolume = 0; *gCurrentPath = NULL; *gCurrentFile = NULL; // Redraw the form if( frmP ) { PrvFormInit(frmP); FrmDrawForm(frmP); PrvDrawTableBorder(frmP); } } /*********************************************************************** * * FUNCTION: PrvSelectFile * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ static void PrvSelectFile(UInt16 index) { MemHandle h; FileBrowserFileInfo fileInfo; FormType * frmP = FrmGetActiveForm(); // Check for error. Will also catch empty SD card. if(PrvGetRecord(index, &fileInfo, &h) != errNone) return; if( fileInfo.attribute & vfsFileAttrDirectory ) { if( !StrCompare("..", fileInfo.fileName) ) { // One directory above UInt32 strLen = StrLen(gCurrentPath); // Skip last '/' <- always there strLen -= 2; while( gCurrentPath[strLen--] != '\\' ) {} // Don't delete the first '/' strLen += 2; gCurrentPath[strLen] = NULL; } else { // One directory below StrCat(gCurrentPath, fileInfo.fileName); StrCat(gCurrentPath, "\\"); } PrvReleaseRecord(index, h); // Clean up database PrvEmptyDB(); // Enumerate with the new path PrvEnumerate(); // Display the path { FieldType *fieldP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserPathField)); SetFieldTextFromStr(fieldP, gCurrentPath, false); } // Reload the table PrvListViewLoadTable(frmP, true); FrmDrawForm(frmP); PrvDrawTableBorder(frmP); } else { StrCopy(gCurrentFile, fileInfo.fileName); PrvReleaseRecord(index, h); // Play it! if( gCallback ) { gCallback(gCurrentVolume, gCurrentPath, gCurrentFile); } if( gReturnForm ) { FrmGotoForm(gReturnForm); } } } /*********************************************************************** * * FUNCTION: PrvFormInit * * DESCRIPTION: This routine initialize the File Browser form. * * PARAMETERS: frmP - Pointer to the form. * * RETURNED: Error Code. * ***********************************************************************/ static Err PrvFormInit(FormType *frmP) { Err err = errNone; UInt32 volumeIterator; Boolean enumerate = false; LocalID dbId; if( !gDB ) { // Open the database dbId = DmFindDatabase(fbCardNumber, fbDBName); if( dbId ) { // If exists open it gDB = DmOpenDatabase(fbCardNumber, dbId, dmModeReadWrite); if(!gDB) { err = DmGetLastErr(); goto Done; } } else { // Else create the database err = DmCreateDatabase(fbCardNumber, fbDBName, fbCreatorID, 'temp', false); if (err != errNone) return err; dbId = DmFindDatabase(fbCardNumber, fbDBName); if( !dbId ) { err = DmGetLastErr(); goto Done; } gDB = DmOpenDatabase(fbCardNumber, dbId, dmModeReadWrite); if( !gDB ) { err = DmGetLastErr(); goto Done; } // Need to enumerate the files enumerate = true; } } // // Get the first card if no volume selected // if( !gCurrentVolume ) { volumeIterator = vfsIteratorStart; err = VFSVolumeEnumerate(&gCurrentVolume, &volumeIterator); if( err == expErrEnumerationEmpty ) { gCurrentVolume = 0; } enumerate = true; } // // Set path to the root if not set // if( !(*gCurrentPath) ) { StrCopy((Char*)gCurrentPath, "\\"); enumerate = true; } // // No file selected for now // *gCurrentFile = NULL; // // Load the files in the Database if needed // if( enumerate ) { PrvEnumerate(); } // // Load the bitmaps // { MemHandle h; BitmapType* bmpP; Coord width, height; WinHandle winH = WinGetDrawWindow(); Err err; h = DmGet1Resource(bitmapRsc, FolderBitmapFamily); bmpP = (BitmapType*)MemHandleLock(h); BmpGetDimensions(bmpP, &width, &height, 0); gFolderWinH = WinCreateOffscreenWindow(width, height, nativeFormat, &err); WinSetDrawWindow(gFolderWinH); WinDrawBitmap(bmpP, 0, 0); MemHandleUnlock(h); DmReleaseResource(h); h = DmGet1Resource(bitmapRsc, DocumentBitmapFamily); bmpP = (BitmapType*)MemHandleLock(h); BmpGetDimensions(bmpP, &width, &height, 0); gDocumentWinH = WinCreateOffscreenWindow(width, height, nativeFormat, &err); WinSetDrawWindow(gDocumentWinH); WinDrawBitmap(bmpP, 0, 0); MemHandleUnlock(h); DmReleaseResource(h); WinSetDrawWindow(winH); } // // Display the path // { FieldType *fieldP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserPathField)); SetFieldTextFromStr(fieldP, gCurrentPath, false); } Done: // // Setup the table // PrvListViewInit(frmP); return err; } /*********************************************************************** * * FUNCTION: PrvFormDeInit * * DESCRIPTION: This routine de-initialize the File Browser form. * * PARAMETERS: frmP - Pointer to the form. * * RETURNED: None. * ***********************************************************************/ static void PrvFormDeInit() { // Release the offscreen windows if( gFolderWinH ) { WinDeleteWindow(gFolderWinH, false); gFolderWinH = 0; } if( gDocumentWinH ) { WinDeleteWindow(gDocumentWinH, false); gDocumentWinH = 0; } // Close the database if( gDB ) { DmCloseDatabase(gDB); gDB = NULL; } } /*********************************************************************** * * FUNCTION: PrvEnumerate * * DESCRIPTION: . * * PARAMETERS: None. * * RETURNED: N/A. * ***********************************************************************/ Err PrvEnumerate() { Err err = errNone; FileRef dirRef = 0; FileRef fileRef = 0; FileInfoType fileInfo; UInt32 fileSize = 0; UInt32 fileIterator = 0; Char *fileName = (Char*)MemPtrNew(MAX_FILENAME_LENGTH); Char *fileName2 = (Char*)MemPtrNew(MAX_FILENAME_LENGTH); fileInfo.nameP = fileName; fileInfo.nameBufLen = MAX_FILENAME_LENGTH; // Clean the database PrvEmptyDB(); // If not the root, add UP directory if( StrCompare( "\\", gCurrentPath) ) { StrCopy( fileName, ".."); fileInfo.attributes = vfsFileAttrDirectory; PrvAddRecord(&fileInfo, 0); } // Open at the current volume and path err = VFSFileOpen(gCurrentVolume, gCurrentPath, vfsModeRead, &dirRef); if( err == errNone ) { fileIterator = vfsIteratorStart; while( fileIterator != vfsIteratorStop ) { err = VFSDirEntryEnumerate(dirRef, &fileIterator, &fileInfo); if( err == errNone ) { if( ! (fileInfo.attributes & UNWANTED_FILES) ) { if( fileInfo.attributes & vfsFileAttrDirectory ) { PrvAddRecord(&fileInfo, 0); } else { StrCopy(fileName2, gCurrentPath); StrCat(fileName2, fileInfo.nameP); err = VFSFileOpen(gCurrentVolume, fileName2, vfsModeRead, &fileRef); err = VFSFileSize(fileRef, &fileSize); PrvAddRecord(&fileInfo, fileSize); err = VFSFileClose(fileRef); } } } } VFSFileClose( dirRef ); } MemPtrFree(fileName); MemPtrFree(fileName2); gFileCount = DmNumRecords(gDB); PrvDBSort(); return err; } /*********************************************************************** * * FUNCTION: PrvDrawTableBorder * * DESCRIPTION: * * PARAMETERS: * * RETURNED: N/A * ***********************************************************************/ static void PrvDrawTableBorder(FormType *frmP) { RectangleType bounds; TablePtr tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); TblGetBounds(tableP, &bounds); WinDrawRectangleFrame(menuFrame, &bounds); } #pragma mark ---------- File Browser DB Functions ---------- /*********************************************************************** * * FUNCTION: FileBrowserDeleteDB * * DESCRIPTION: This routine should be called when the app stops. * It deletes the temporary database. * * PARAMETERS: None. * * RETURNED: Error Code. * ***********************************************************************/ Err FileBrowserDeleteDB() { LocalID dbID; UInt16 cardNo; Err err = errNone; if(!gDB) { // Open the database dbID = DmFindDatabase(fbCardNumber, fbDBName); if( dbID ) { // If exists open it gDB = DmOpenDatabase(fbCardNumber, dbID, dmModeReadWrite); if(!gDB) { err = DmGetLastErr(); return err; } } else return err; } err = DmOpenDatabaseInfo(gDB, &dbID, 0, 0, &cardNo, 0); err = DmCloseDatabase(gDB); err = DmDeleteDatabase(cardNo, dbID); return err; } /*********************************************************************** * * FUNCTION: PrvEmptyDB * * DESCRIPTION: This routine deletes all the records of the temp database. * * PARAMETERS: None. * * RETURNED: Error Code. * ***********************************************************************/ static Err PrvEmptyDB() { Err err = errNone; UInt16 index = DmNumRecords(gDB); while (index--) { err = DmRemoveRecord(gDB, index); } return err; } /*********************************************************************** * * FUNCTION: PrvAddRecord * * DESCRIPTION: This routine adds a record to the temp database * * PARAMETERS: fileInfoP - Pointer to a FileInfo Structure * * RETURNED: Error Code * ***********************************************************************/ static Err PrvAddRecord(FileInfoType* fileInfoP, UInt32 fileSize) { Err err = errNone; void* memLockP = NULL; MemHandle recordHandle = NULL; UInt32 recordSize = 0; UInt16 recordIndex = dmMaxRecordIndex; UInt32 offset = 0; FileBrowserFileInfo fbFileInfo; // Local store fbFileInfo.selected = false; fbFileInfo.attribute = fileInfoP->attributes; fbFileInfo.fileName = fileInfoP->nameP; fbFileInfo.fileSize = fileSize; recordSize = (StrLen(fbFileInfo.fileName)+1); recordHandle = DmNewRecord(gDB, &recordIndex, recordSize + sizeof(UInt32) + sizeof(UInt16) + sizeof(Boolean)); if( !recordHandle ) { err = DmGetLastErr(); return err; } memLockP = MemHandleLock(recordHandle); // Write selection offset = 0; err = DmWrite( memLockP, offset, &fbFileInfo.selected, sizeof(Boolean)); if(err) goto Done; offset += sizeof(Boolean); err = DmWrite( memLockP, offset, &fbFileInfo.attribute, sizeof(UInt16)); if(err) goto Done; offset += sizeof(UInt16); err = DmWrite( memLockP, offset, &fbFileInfo.fileSize, sizeof(UInt32)); if(err) goto Done; offset += sizeof(UInt32); err = DmWrite( memLockP, offset, fbFileInfo.fileName, recordSize); if(err) goto Done; Done: MemHandleUnlock(recordHandle); err = DmReleaseRecord(gDB, recordIndex, true); if( err ) { DmRemoveRecord(gDB, recordIndex); } return err; } /*********************************************************************** * * FUNCTION: PrvGetRecord * * DESCRIPTION: This routine returns the file info for the given index * * PARAMETERS: index - File index in the database * fileInfoP - File info Ptr * * RETURNED: * ***********************************************************************/ static Err PrvGetRecord(UInt16 index, FileBrowserFileInfo* fileInfoP, MemHandle* hP) { Err err = errNone; MemHandle recH; UInt8 *recP = NULL; recH = DmQueryRecord(gDB, index); if (recH == NULL) { err = DmGetLastErr(); goto Done; } else *hP = recH; recP = (UInt8 *)MemHandleLock(recH); if (recP == NULL) { err = memErrChunkNotLocked; goto Done; } fileInfoP->selected = (Boolean)*recP; recP += sizeof(Boolean); fileInfoP->attribute = MisalignedReadBEUInt16(recP, 0); recP += sizeof(UInt16); fileInfoP->fileSize = MisalignedReadBEUInt32(recP, 0); recP += sizeof(UInt32); fileInfoP->fileName = (Char*)recP; Done: return err; } /*********************************************************************** * * FUNCTION: PrvReleaseRecord * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ static void PrvReleaseRecord(UInt16 index, MemHandle h) { index = 0;// To prevent some annoying warnings ( Ignore ) MemHandleUnlock(h); } /*********************************************************************** * * FUNCTION: * * DESCRIPTION: * * PARAMETERS: * * RETURNED: * ***********************************************************************/ static Int16 PrvDBCompareRecords( Char* r1P, Char* r2P, Int16 UNUSED_PARAM(param), SortRecordInfoType* UNUSED_PARAM(info1), SortRecordInfoType* UNUSED_PARAM(info2), MemHandle UNUSED_PARAM(appInfoH)) { Int16 result; FileBrowserFileInfo rec1, rec2; rec1.selected = (Boolean)*r1P; r1P += sizeof(Boolean); rec1.attribute = MisalignedReadBEUInt16(r1P, 0); r1P += sizeof(UInt16) + sizeof(UInt32); rec1.fileName = (Char*)r1P; rec2.selected = (Boolean)*r2P; r2P += sizeof(Boolean); rec2.attribute = MisalignedReadBEUInt16(r2P, 0); r2P += sizeof(UInt16) + sizeof(UInt32); rec2.fileName = (Char*)r2P; // First check to display the folder first if (rec1.attribute & vfsFileAttrDirectory) { if (!(rec2.attribute & vfsFileAttrDirectory)) return -1; } else if (rec2.attribute & vfsFileAttrDirectory) return 1; // Alphabetize; result = TxtCompare( rec1.fileName, // const Char *s1 0xFFFF, // UInt16 s1Len, NULL, // UInt16 *s1MatchLen, rec2.fileName, // const Char *s2, 0xFFFF, // UInt16 s2Len, NULL); // UInt16 *s2MatchLen return result; } /************************************************************ * * FUNCTION: * * DESCRIPTION: * * PARAMETERS: * * RETURNS: * *************************************************************/ static void PrvDBSort() { DmInsertionSort(gDB, (DmComparF *)&PrvDBCompareRecords, 0); } #pragma mark ---------- File Browser List View ---------- /*********************************************************************** * * FUNCTION: PrvListViewInit * * DESCRIPTION: This routine initializes the table * * PARAMETERS: frmP - Pointer to a form * * RETURNED: N/A * ***********************************************************************/ static void PrvListViewInit(FormType *frmP) { UInt16 rowCount; TablePtr tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); gRowCount = rowCount = TblGetNumberOfRows(tableP); // Init the row elements while( rowCount-- ) { TblSetRowUsable(tableP, rowCount, false); TblSetItemStyle(tableP, rowCount, FILE_COLUMN, customTableItem); } TblHasScrollBar(tableP, true); TblSetColumnUsable(tableP, FILE_COLUMN, true); TblSetCustomDrawProcedure(tableP, FILE_COLUMN, PrvListViewDrawFile); // Load the table PrvListViewLoadTable(frmP, false); } /*********************************************************************** * * FUNCTION: PrvListViewDrawFile * * DESCRIPTION: This routine draws a file in the table * * PARAMETERS: tableP - Pointer to the table * row - The row to draw * column - The column to draw * boundsP - Pointer to the element bound * * RETURNED: N/A * ***********************************************************************/ static void PrvListViewDrawFile(void *tableP, Int16 row, Int16 column, RectangleType *boundsP) { UInt16 index; MemHandle h; FileBrowserFileInfo fileInfo; WinHandle winH; Char * ptr; UInt16 titleLen; Char text[32]; UInt32 fileSizeWidth = 0; Err err = errNone; column = 0; // ignore, to prevent some annoying warnings index = TblGetRowID(tableP, row); err = PrvGetRecord( index, &fileInfo, &h); if( err ) goto Done; // Draw icon ptr = StrChr (fileInfo.fileName, linefeedChr); titleLen = (ptr == NULL ? StrLen (fileInfo.fileName) : (UInt16) (ptr - fileInfo.fileName)); if( fileInfo.attribute & vfsFileAttrDirectory ) { RectangleType rct; winH = gFolderWinH; WinGetWindowFrameRect(winH, &rct); WinCopyRectangle(winH, 0, &rct, boundsP->topLeft.x, boundsP->topLeft.y + 1, winPaint); } else { RectangleType rct; winH = gDocumentWinH; WinGetWindowFrameRect(winH, &rct); WinCopyRectangle(winH, 0, &rct, boundsP->topLeft.x, boundsP->topLeft.y + 1, winPaint); } if( !(fileInfo.attribute & vfsFileAttrDirectory) ) { // Display the file size if(fileInfo.fileSize > 1048576) { // Use the KB style (123.4 MB) UInt32 mantissa = fileInfo.fileSize / 1048576; UInt32 fraction = ( fileInfo.fileSize - mantissa * 1048576 ) / 104858; StrPrintF(text, "%ld.%ld M", mantissa, fraction); } else if(fileInfo.fileSize > 1024) { // Use the KB style (123.4 KB) UInt32 mantissa = fileInfo.fileSize / 1024; UInt32 fraction = ( fileInfo.fileSize - mantissa * 1024 ) / 103; StrPrintF(text, "%ld.%ld K", mantissa, fraction); } else { // Use the B style (24 B) StrPrintF(text, "%ld B", fileInfo.fileSize); } // Get the length fileSizeWidth = FntCharsWidth(text, StrLen(text)); WinDrawChars(text, StrLen(text), boundsP->topLeft.x + boundsP->extent.x - fileSizeWidth, boundsP->topLeft.y); //fileSizeWidth + 4; // Give me some space } // Draw File Name if( FntWidthToOffset (fileInfo.fileName, titleLen, boundsP->extent.x - 15 - fileSizeWidth, NULL, NULL) == titleLen) { WinDrawChars (fileInfo.fileName, titleLen, boundsP->topLeft.x + 15, boundsP->topLeft.y); } else { Int16 titleWidth; titleLen = FntWidthToOffset (fileInfo.fileName, titleLen, boundsP->extent.x - 15 - fileSizeWidth - FntCharWidth (chrEllipsis), NULL, &titleWidth); WinDrawChars (fileInfo.fileName, titleLen, boundsP->topLeft.x + 15, boundsP->topLeft.y); WinDrawChar (chrEllipsis, boundsP->topLeft.x + 15 + titleWidth, boundsP->topLeft.y); } // Release the record PrvReleaseRecord(index, h); Done: return; } /*********************************************************************** * * FUNCTION: PrvListViewLoadTable * * DESCRIPTION: This routine loads the table. * * PARAMETERS: frmP - Pointer to a form. * * RETURNED: N/A * ***********************************************************************/ void PrvListViewLoadTable(FormType *frmP, Boolean redraw) { UInt16 row; UInt16 rowCount; UInt16 displayCount; TablePtr tableP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileTable)); ScrollBarPtr barP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, FileBrowserFileScrollBar)); rowCount = TblGetNumberOfRows(tableP); //If scrolling or 5-way have been used and there is only 1 file, reset gTopIndex if (((gScrolling == true)||(gUsedUpDown == true)) && gFileCount == 1){ gTopIndex = 0; } displayCount = gFileCount - gTopIndex; for(row = 0; row < gRowCount; row++) { if( row < displayCount ) { TblSetRowID(tableP, row, row + gTopIndex); TblSetRowUsable(tableP, row, true); TblSetRowSelectable(tableP, row, true); } else { TblSetRowUsable(tableP, row, false); TblSetRowSelectable(tableP, row, false); } } if( redraw ) { TblEraseTable(tableP); TblDrawTable(tableP); } if( gFileCount <= gRowCount ) { SclSetScrollBar(barP, 0, 0, 0, gRowCount); } else { SclSetScrollBar(barP, gTopIndex, 0, gFileCount - gRowCount, gRowCount); } } /*@}*/