From 17349a5e426dc7acf1216a3767a22f69974cbca0 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Mon, 14 Apr 2008 21:45:08 -0400 Subject: Initial commit. --- Liaison/FileTableDelegate.m | 1345 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1345 insertions(+) create mode 100644 Liaison/FileTableDelegate.m (limited to 'Liaison/FileTableDelegate.m') diff --git a/Liaison/FileTableDelegate.m b/Liaison/FileTableDelegate.m new file mode 100644 index 0000000..cd8591a --- /dev/null +++ b/Liaison/FileTableDelegate.m @@ -0,0 +1,1345 @@ +#import "FileTableDelegate.h" + +#import "InspectorController.h" +#import "ImageAndTextCell.h" +#import "LoadPanelController.h" +#import "NIBConnector.h" +#import "PluginManager.h" + +#include +#include + +// XXX - should use SEL instead of NSString. +struct SortContext { + BOOL ascending; + SEL compareMethod, getMethod; +}; + +int contextSorter(id file1, id file2, void *someContext) +{ + struct SortContext *context; + id leftVal, rightVal; + + context = (struct SortContext *)someContext; + if (context->ascending) { + leftVal = [file1 performSelector: context->getMethod]; + rightVal = [file2 performSelector: context->getMethod]; + } else { + leftVal = [file2 performSelector: context->getMethod]; + rightVal = [file1 performSelector: context->getMethod]; + } + + if (rightVal == nil) { + if (leftVal == nil) + return 0; + else + return -1; + } else if (leftVal == nil) + return 1; + + return (int)[leftVal performSelector: context->compareMethod + withObject: rightVal]; +} + +static NSString * +myLocalizedString(NSString *aString) +{ + return NSLocalizedStringFromTable(aString, @"WindowElements", @""); +} + +static void +logRect(NSString *desc, NSRect aRect) +{ + [LiLog logAsDebug: @"%@, (%f, %f, %f, %f)", desc, aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height]; +} + +@interface LiFileHandle (GUIStuff) +- (void)revealInFinder; +@end + +@implementation LiFileStore (BatchPathAdditions) +- (BOOL)isValidPath: (NSString *)aPath +{ + NSString *filename; + + filename = [aPath lastPathComponent]; + if ([filename hasPrefix: @"."] || + [filename isEqualToString: @"Icon\r"]) + return NO; + + return YES; +} + +- (BOOL)addURLs: (NSArray *)aURLList toGroup: (NSString *)aGroup +{ + NSURL *fileURL; + int i, numFiles; + + if ([aURLList count] == 0) + return YES; + + numFiles = [aURLList count]; + + i = 0; + for (fileURL in aURLList) { + LiFileHandle *tmpFile; + + NS_DURING + tmpFile = [self addURL: fileURL]; + + if (aGroup != nil) { + [tmpFile addToGroup: aGroup]; + } + NS_HANDLER + [LiLog logAsWarning: @"Couldn't add file: %@ - %@", [localException name], [localException reason]]; + NS_ENDHANDLER + + i++; + } + + return YES; +} + +- (NSArray *)makeURLsFromPaths: (NSArray *)aFileList toGroup: (NSString *)aGroup +{ + LoadPanelController *loadPanelController; + NSMutableArray *myFileList; + NSString *path; + int i, fileCount; + + loadPanelController = [[NIBConnector connector] loadPanelController]; + [loadPanelController setStatus: myLocalizedString(@"LiLoadingDirectory")]; + [loadPanelController setProgress: 100.0]; + [loadPanelController setIndeterminantProgress: YES]; + [loadPanelController update]; + fileCount = [aFileList count]; + i = 0; + + myFileList = [NSMutableArray array]; + for (path in aFileList) { + if ((i % 10) == 0) { + [loadPanelController setPath: [path lastPathComponent]]; + [loadPanelController update]; + } + + if ([self isValidPath: path]) { + NSFileManager *defaultManager; + BOOL isBundle; + BOOL isDirectory; + + isDirectory = NO; + defaultManager = [NSFileManager defaultManager]; + [defaultManager fileExistsAtPath: path isDirectory: &isDirectory]; + if ([path hasSuffix: @".app"] || + [[NSWorkspace sharedWorkspace] isFilePackageAtPath: path]) + isBundle = YES; + else + isBundle = NO; + + if (isDirectory && !isBundle) { + struct dirent *dirp; + DIR *directory; + NSAutoreleasePool *rp; + NSMutableArray *dirContents; + int j; + + [LiLog logAsDebug: @"Recursing into: %@", path]; + [LiLog indentDebugLog]; + + // Let people know we're working in a subdirectory. + j = 0; + + dirContents = [[NSMutableArray alloc] init]; + directory = opendir([path UTF8String]); + while ((dirp = readdir(directory)) != NULL) { + NSString *subPath; + + subPath = [NSString stringWithUTF8String: dirp->d_name]; + if ([self isValidPath: subPath] == YES) { + NSString *fullPath; + + if ((j % 10) == 0) { + [loadPanelController update]; + } + + fullPath = [path stringByAppendingPathComponent: subPath]; + [dirContents addObject: fullPath]; + } + j++; + } + closedir(directory); + + rp = [[NSAutoreleasePool alloc] init]; + [self addURLs: [self makeURLsFromPaths: dirContents toGroup: aGroup] + toGroup: aGroup]; + [rp release]; + [dirContents release]; + + [LiLog unindentDebugLog]; + } else { + [LiLog logAsDebug: @"Adding %@ to file list", path]; + [loadPanelController setPath: [path lastPathComponent]]; + [myFileList addObject: [NSURL fileURLWithPath: path]]; + } + } + i++; + } + + return myFileList; +} + +- (NSArray *)addPaths: (NSArray *)aPathList toGroup: (NSString *)aGroup +{ + if ([aPathList count] > 0) { + LoadPanelController *loadPanelController; + NSArray *fileList; + + loadPanelController = [[NIBConnector connector] loadPanelController]; + [loadPanelController show]; + fileList = [self makeURLsFromPaths: aPathList toGroup: aGroup]; + [self addURLs: fileList toGroup: aGroup]; + [loadPanelController hide]; + [self synchronize]; + } + + return nil; +} +@end + +@implementation FileTableDelegate (LiTableViewDelegate) +- (void)tableViewDidBecomeFirstResponder: (NSTableView *)aTableView +{ + [LiLog logAsDebug: @"[FileTableDelegate becameFirstResponder]"]; + [LiLog indentDebugLog]; + if ([tableView numberOfSelectedRows] == 1) { + LiFileHandle *theRecord; + + theRecord = [self fileAtIndex: [tableView selectedRow]]; + // Auto-update a clicked file. + [theRecord update]; + [[theRecord fileStore] synchronize]; + [inspectorController setFile: theRecord]; + } + [LiLog unindentDebugLog]; +} + +- (void)deleteSelectedRowsInTableView: (NSTableView *)aTableView +{ + NSEnumerator *rowEnum; + NSString *myGroup; + NSMutableArray *selectedFiles; + NSNumber *row; + + rowEnum = [aTableView selectedRowEnumerator]; + selectedFiles = [NSMutableArray array]; + while ((row = [rowEnum nextObject]) != nil) { + LiFileHandle *record; + + record = [self fileAtIndex: [row intValue]]; + [selectedFiles addObject: record]; + } + + [aTableView deselectAll: self]; + + myGroup = [self group]; + if (myGroup == nil) { + LiFileHandle *file; + + for (file in selectedFiles) { + [[self fileStore] removeFileHandle: file]; + } + } else { + LiFileHandle *file; + + for (file in selectedFiles) { + [LiLog logAsDebug: @"Removing %@ from %@", [file filename], myGroup]; + [LiLog logAsDebug: @"old groups: %@", [[file groups] description]]; + [file removeFromGroup: myGroup]; + [LiLog logAsDebug: @"new groups: %@", [[file groups] description]]; + } + } + [[self fileStore] synchronize]; +} +@end + +@implementation FileTableDelegate (TableViewDataSource) +- (int)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return [[self sortedList] count]; +} + +- (id)tableView: (NSTableView *)aTableView +objectValueForTableColumn: (NSTableColumn *)aTableColumn + row: (int)rowIndex +{ + LiFileHandle *record; + LiBrowserColumn *col; + + col = [self columnForIdentifier: [aTableColumn identifier]]; + record = [self fileAtIndex: rowIndex]; + return [col objectForRecord: record]; +} + +- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex +{ + LiFileHandle *record; + LiBrowserColumn *col; + + if (rowIndex < 0 || rowIndex >= (int)[[self sortedList] count]) + return; + + col = [self columnForIdentifier: [aTableColumn identifier]]; + record = [self fileAtIndex: rowIndex]; + [col setObject: anObject forRecord: record]; + + [[record fileStore] synchronize]; +} + +- (NSDragOperation)tableView: (NSTableView *)aTableView + validateDrop: (id )sender + proposedRow: (int)index + proposedDropOperation: (NSDragOperation)operation; +{ + NSDragOperation dragOp; + + dragOp = NSDragOperationNone; + if ([sender draggingSource] != tableView && + [[self fileStore] isEditable] == YES) { + NSPasteboard *pboard; + + pboard = [sender draggingPasteboard]; + if ([pboard availableTypeFromArray: + [NSArray arrayWithObjects: NSFilenamesPboardType, NSFilesPromisePboardType, nil]]) { + [aTableView setDropRow: -1 dropOperation: NSTableViewDropOn]; + dragOp = NSDragOperationCopy; + } + } + + return dragOp; +} + +- (BOOL)tableView: (NSTableView *)aTableView + acceptDrop: (id )aSender + row: (int)anIndex + dropOperation: (NSTableViewDropOperation)anOperation +{ + NSArray *pathList; + NSPasteboard *pboard; + + pboard = [aSender draggingPasteboard]; + + pathList = nil; + if ([pboard availableTypeFromArray: + [NSArray arrayWithObject: NSFilenamesPboardType]]) { + pathList = [pboard propertyListForType: NSFilenamesPboardType]; + } + + // Handle promised files. + if ([[pboard types] containsObject: NSFilesPromisePboardType]) { + NSEnumerator *pathEnum; + NSMutableArray *promisedPaths; + NSString *path; + NSURL *dropLocation; + + dropLocation = [NSURL fileURLWithPath: + [[Preferences sharedPreferences] downloadDirectory]]; + pathEnum = [[aSender namesOfPromisedFilesDroppedAtDestination: dropLocation] objectEnumerator]; + promisedPaths = [NSMutableArray array]; + while ((path = [pathEnum nextObject]) != nil) { + [promisedPaths addObject: [[dropLocation path] stringByAppendingPathComponent: path]]; + } + pathList = promisedPaths; + } + + if ([pathList count] > 0) { + [[self fileStore] addPaths: pathList toGroup: [self group]]; + return YES; + } + + // XXX - should select the added songs now. + + return NO; + +} + +- (BOOL)tableView: (NSTableView *)aTableView + writeRows: (NSArray *)someRows + toPasteboard: (NSPasteboard *)aPboard +{ + NSMutableArray *liaisonPboard, *filenamePboard, *promisePboard; + NSMutableArray *typeList; + NSNumber *row; + + liaisonPboard = [NSMutableArray array]; + filenamePboard = [NSMutableArray array]; + promisePboard = [NSMutableArray array]; + + for (row in someRows) { + LiFileHandle *file; + NSURL *url; + + file = [self fileAtIndex: [row intValue]]; + [liaisonPboard addObject: file]; + url = [file url]; + if ([url isFileURL] == YES) { + [filenamePboard addObject: [url path]]; + } + } + + typeList = [NSMutableArray array]; + if ([liaisonPboard count] > 0) + [typeList addObject: LiaisonPboardType]; + if ([filenamePboard count] > 0) + [typeList addObject: NSFilenamesPboardType]; + // Make an HFS promise. + + if ([typeList count] > 0) { + [aPboard declareTypes: typeList owner: self]; + + if ([liaisonPboard count] > 0) { + NSData *liaisonPboardData; + + liaisonPboardData = [NSKeyedArchiver archivedDataWithRootObject: + liaisonPboard]; + if ([aPboard setData: liaisonPboardData + forType: LiaisonPboardType] == NO) + return NO; + } + + if ([filenamePboard count] > 0) { + if ([aPboard setPropertyList: filenamePboard + forType: NSFilenamesPboardType] == NO) + return NO; + } + return YES; + } + return NO; +} +@end + +@implementation FileTableDelegate (TableViewDelegate) +- (void)tableView: (NSTableView*)aTableView +didClickTableColumn: (NSTableColumn *)aTableColumn +{ + LiBrowserColumn *col; + + col = [self columnForIdentifier: [aTableColumn identifier]]; + if ([col compareMethod]) { + struct SortContext context; + + if ([self selectedColumn] && [self selectedColumn] == aTableColumn) { + if (isAscending) + isAscending = NO; + else + aTableColumn = nil; // XXX, but it works. + } else + isAscending = YES; + + context.ascending = isAscending; + context.getMethod = [col getMethod]; + context.compareMethod = [col compareMethod]; + [self saveSelectionOfTableView: tableView]; + [self setSelectedColumn: aTableColumn withContext: &context]; + [self redisplay]; + [self restoreSelectionToTableView: tableView refresh: YES]; + } +} + +- (BOOL)tableView: (NSTableView *)theTable shouldSelectRow: (int)theRow +{ + if (theRow < 0 || (int)[[self sortedList] count] <= theRow) + return NO; + return YES; +} + +- (BOOL)tableView: (NSTableView *)aTableView +shouldEditTableColumn: (NSTableColumn *)aTableColumn + row: (int)rowIndex +{ + LiFileHandle *record; + + record = [self fileAtIndex: rowIndex]; + return [record isEditable]; +} + +- (void)tableView: (NSTableView *)aTableView + copyRow: (int)aRow +{ + [LiLog logAsDebug: @"[tableView copyRow]"]; +} + +- (void)tableViewSelectionDidChange: (NSNotification *)aNotification +{ + [LiLog logAsDebug: @"[FileTableDelegate tableViewSelectionDidChange: (notification)]"]; + [LiLog indentDebugLog]; + if ([tableView numberOfSelectedRows] == 1) { + LiFileHandle *theRecord; + + theRecord = [self fileAtIndex: [tableView selectedRow]]; + // Auto-update a clicked file. + [theRecord update]; + [[theRecord fileStore] synchronize]; + [inspectorController setFile: theRecord]; + } + [LiLog unindentDebugLog]; +} + +- (void)doDoubleClickInTable: (NSTableView *)aTable; +{ + NSEnumerator *rowEnum; + NSNumber *selectedRow; + + rowEnum = [aTable selectedRowEnumerator]; + while ((selectedRow = [rowEnum nextObject]) != nil) { + LiFileHandle *file; + + file = [self fileAtIndex: [selectedRow intValue]]; + [file open]; + } +} + +- (void)tableViewColumnDidMove: (NSNotification *)aNotification +{ + NSEnumerator *colEnum; + NSMutableArray *colOrder; + NSMutableDictionary *listPrefs; + NSTableColumn *column; + + listPrefs = [self listPrefs]; + colOrder = [NSMutableArray array]; + colEnum = [[[self tableView] tableColumns] objectEnumerator]; + while ((column = [colEnum nextObject]) != nil) { + [colOrder addObject: [column identifier]]; + } + + [listPrefs setObject: colOrder forKey: @"columnOrder"]; + [self setListPrefs: listPrefs]; +} + +- (void)tableViewColumnDidResize: (NSNotification *)aNotification +{ + NSMutableDictionary *colPrefs; + NSNumber *colSize; + NSTableColumn *column; + + column = [[aNotification userInfo] objectForKey: @"NSTableColumn"]; + if (column != nil) { + colPrefs = [self columnPrefsForIdentifier: [column identifier]]; + colSize = [NSNumber numberWithFloat: [column width]]; + [colPrefs setObject: colSize forKey: @"width"]; + [self setColumnPrefs: colPrefs forIdentifier: [column identifier]]; + } +} +@end + +@implementation FileTableDelegate +- (void)openPanelDidEnd: (NSOpenPanel *)openPanel + returnCode: (int)returnCode + contextInfo: (void *)context +{ + [openPanel close]; + if (returnCode == NSOKButton) { + [[self fileStore] addPaths: [openPanel filenames] toGroup: [self group]]; + } +} + +- (IBAction)addFiles: (id)sender +{ + NSOpenPanel *openPanel; + + if ([[self fileStore] isEditable]) { + openPanel = [NSOpenPanel openPanel]; + [openPanel setTitle: myLocalizedString(@"LiLoadPanelTitle")]; + [openPanel setAllowsMultipleSelection: YES]; + [openPanel setCanChooseDirectories: YES]; + [openPanel setCanChooseFiles: YES]; + + [openPanel beginSheetForDirectory: nil file: nil types: nil + modalForWindow: [NSApp mainWindow] modalDelegate: self + didEndSelector: @selector(openPanelDidEnd:returnCode:contextInfo:) + contextInfo: nil]; + } +} + +- (IBAction)openSelectedFiles: (id)sender +{ + NSEnumerator *selectionEnum; + NSNumber *row; + + selectionEnum = [tableView selectedRowEnumerator]; + while ((row = [selectionEnum nextObject]) != nil) { + LiFileHandle *fileHandle; + + fileHandle = [self fileAtIndex: [row intValue]]; + [fileHandle open]; + } +} + +- (IBAction)revealInFinder: (id)sender +{ + NSEnumerator *rowEnum; + NSNumber *row; + + rowEnum = [tableView selectedRowEnumerator]; + while ((row = [rowEnum nextObject]) != nil) { + LiFileHandle *tmpFile; + + tmpFile = [self fileAtIndex: [row intValue]]; + [tmpFile revealInFinder]; + } +} + +- (NSDictionary *)browserColumns +{ + NSEnumerator *pluginEnum; + NSMutableDictionary *browserColumns; + NSObject *plugin; + + browserColumns = [NSMutableDictionary dictionary]; + pluginEnum = [[[PluginManager defaultManager] browserPlugins] objectEnumerator]; + while ((plugin = [pluginEnum nextObject]) != nil) { + LiBrowserColumn *col; + NSEnumerator *colEnum; + + colEnum = [[plugin columns] objectEnumerator]; + while ((col = [colEnum nextObject]) != nil) { + NSString *identifier; + + identifier = [NSString stringWithFormat: @"%@:%@", + NSStringFromClass([plugin class]), [col identifier]]; + [browserColumns setObject: col forKey: identifier]; + } + } + + return browserColumns; +} + +- (LiBrowserColumn *)columnForIdentifier: (NSString *)anIdentifier +{ + return [theTableColumns objectForKey: anIdentifier]; +} + +- (void)showColumnWithIdentifier: (NSString *)anIdentifier +{ + LiBrowserColumn *col; + NSMutableDictionary *shownColumns; + + shownColumns = [self shownColumns]; + if (shownColumns == nil) { + shownColumns = [NSMutableDictionary dictionary]; + [self setShownColumns: shownColumns]; + } + + col = [self columnForIdentifier: anIdentifier]; + if (col && [shownColumns objectForKey: anIdentifier] == nil) { + NSDictionary *colPrefs; + NSTableColumn *tableColumn; + + colPrefs = [self columnPrefsForIdentifier: anIdentifier]; + tableColumn = [[[NSTableColumn alloc] initWithIdentifier: anIdentifier] autorelease]; + [tableColumn setEditable: [col editable]]; + [tableColumn setDataCell: [col cell]]; + [tableColumn setResizable: [col resizable]]; + if ([col resizable]) { + NSNumber *colWidth; + + colWidth = [colPrefs objectForKey: @"width"]; + if (colWidth != nil) + [col setWidth: colWidth]; + } + + if ([col showsHeader]) + [[tableColumn headerCell] setStringValue: [col name]]; + else + [[tableColumn headerCell] setStringValue: @""]; + + if ([col width]) + [tableColumn setWidth: [[col width] floatValue]]; + + [shownColumns setObject: tableColumn forKey: anIdentifier]; + + [tableView addTableColumn: tableColumn]; + } +} + +- (void)removeColumnWithIdentifier: (NSString *)anIdentifier +{ + NSTableColumn *col; + + col = [[self shownColumns] objectForKey: anIdentifier]; + if (col != nil) { + [[self shownColumns] removeObjectForKey: anIdentifier]; + [tableView removeTableColumn: col]; + } +} + +- (id)init +{ + self = [super init]; + + theTableColumns = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (void)dealloc +{ + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter removeObserver: self]; + + [ascendingSortingImage release]; + [descendingSortingImage release]; + [self setActiveList: nil]; + [self setFileStore: nil]; + [self setFilter: nil]; + [self setSearchString: nil]; + + [theTableColumns release]; + + [super dealloc]; +} + +- (void)awakeFromNib +{ + NSArray *shownColumns; + NSDictionary *listPrefs; + NSEnumerator *columnEnum; + NSString *columnID; + + [LiLog logAsDebug: @"[FileTableDelegate awakeFromNib]"]; + [LiLog indentDebugLog]; + + ascendingSortingImage = [[NSImage imageNamed: @"SortAscending.gif"] retain]; + descendingSortingImage = [[NSImage imageNamed: @"SortDescending.gif"] retain]; + + [tableView setTarget: self]; + [tableView setDoubleAction: @selector(doDoubleClickInTable:)]; + + // XXX + theTableColumns = (NSMutableDictionary *)[self browserColumns]; + [theTableColumns retain]; + + listPrefs = [self listPrefs]; + shownColumns = [listPrefs objectForKey: @"columnOrder"]; + for (columnID in shownColumns) { + [self showColumnWithIdentifier: columnID]; + } + + if ([[[self tableView] tableColumns] count] == 0) { + columnEnum = [theTableColumns keyEnumerator]; + while ((columnID = [columnEnum nextObject]) != nil) { + [LiLog logAsDebug: @"showCol: %@", columnID]; + [self showColumnWithIdentifier: columnID]; + } + } + + /* Register for Drag-and-Drop operation. */ + [tableView registerForDraggedTypes: + [NSArray arrayWithObjects: NSFilenamesPboardType, NSFilesPromisePboardType, NSHTMLPboardType, NSTIFFPboardType, NSPICTPboardType, NSURLPboardType, NSFileContentsPboardType, nil]]; + + [statusLine setStringValue: @""]; + + [LiLog unindentDebugLog]; +} + +- (void)respondToFileChanged: (NSNotification *)aNotification +{ + LiFileHandle *file; + NSArray *addedFileList, *changedFileList, *removedFileList; + NSDictionary *fileDict; + NSEnumerator *fileEnum; + BOOL needsRedisplay; + + needsRedisplay = NO; + + addedFileList = [[aNotification userInfo] objectForKey: LiFilesAdded]; + changedFileList = [[aNotification userInfo] objectForKey: LiFilesChanged]; + removedFileList = [[aNotification userInfo] objectForKey: LiFilesRemoved]; + + fileEnum = [addedFileList objectEnumerator]; + while (needsRedisplay == NO && + (file = [fileEnum nextObject]) != nil) { + if ([file matchesFilter: [self filter]]) + needsRedisplay = YES; + } + + fileEnum = [changedFileList objectEnumerator]; + while (needsRedisplay == NO && + (fileDict = [fileEnum nextObject]) != nil) { + LiFileHandle *tmpHandle; + NSDictionary *oldAttributes; + + tmpHandle = [fileDict objectForKey: @"LiFileHandleAttribute"]; + oldAttributes = [fileDict objectForKey: LiFileOldAttributes]; + if ([[self fileStore] attributes: oldAttributes matchFilter: [self filter]] || + [tmpHandle matchesFilter: [self filter]]) + needsRedisplay = YES; + } + + fileEnum = [removedFileList objectEnumerator]; + while (needsRedisplay == NO && + (fileDict = [fileEnum nextObject]) != nil) { + if ([[self fileStore] attributes: [fileDict objectForKey: LiFileOldAttributes] + matchFilter: [self filter]]) { + needsRedisplay = YES; + } + } + + if (needsRedisplay) { + [self saveSelectionOfTableView: tableView]; + [self redisplay]; + [self restoreSelectionToTableView: tableView refresh: YES]; + } +} + +- (int)numberOfFiles +{ + return [[self sortedList] count]; +} + +- (LiFileHandle *)fileAtIndex: (int)index +{ + return [[self sortedList] objectAtIndex: index]; +} + +- (void)addAttributeFilter: (LiFilter *)aFilter +{ + [LiLog logAsDebug: @"[FileTableDelegate addAttributeFilter: %@]", [aFilter description]]; + [LiLog indentDebugLog]; + + [self setFilter: aFilter]; + +#if 0 + filters = [self attributeFilters]; + attrEnum = [someFilters keyEnumerator]; + while ((attribute = [attrEnum nextObject]) != nil) + [filters setObject: [someFilters objectForKey: attribute] + forKey: attribute]; + + [LiLog unindentDebugLog]; +#endif +} + +#if 0 +- (id)filterForAttribute: (NSString *)anAttribute +{ + [LiLog logAsDebug: @"[FileTableDelegate filterForAttribute: %@]", anAttribute]; + [[LiLog indentDebugLog] logAsDebug: @"filters: %@", [[self attributeFilters] description]]; + [LiLog unindentDebugLog]; + return [[self attributeFilters] objectForKey: anAttribute]; +} +#endif + +- (void)removeAttributeFilter: (LiFilter *)aFilter +{ + [LiLog logAsDebug: @"[FileTableDelegate removeAttributeFilter: %@]", [aFilter description]]; + [self setFilter: nil]; + +#if 0 + filters = [self attributeFilters]; + attrEnum = [someFilters keyEnumerator]; + while ((attribute = [attrEnum nextObject]) != nil) + [filters removeObjectForKey: attribute]; +#endif +} + +- (void)saveSelectionOfTableView: (NSTableView *)aTableView +{ + NSEnumerator *theEnum; + NSMutableSet *savedSelection; + NSNumber *rowNum; + + savedSelection = [self savedSelection]; + if (savedSelection == nil) { + savedSelection = [[NSMutableSet alloc] init]; + theEnum = [aTableView selectedRowEnumerator]; + while ((rowNum = [theEnum nextObject]) != nil) { + id item; + + item = [[self sortedList] objectAtIndex: [rowNum intValue]]; + [savedSelection addObject: item]; + } + [self setSavedSelection: savedSelection]; + } +} + +- (void)restoreSelectionToTableView: (NSTableView *)aTableView + refresh: (BOOL)inRefresh +{ + NSMutableSet *savedSelection; + id item; + int savedLastRow; + + [aTableView deselectAll: self]; + + savedLastRow = -1; + savedSelection = [self savedSelection]; + if (savedSelection != nil) { + for (item in savedSelection) { + int row; + + row = [[self sortedList] indexOfObject: item]; + if (row != NSNotFound) { + [aTableView selectRow: row byExtendingSelection: YES]; + savedLastRow = row; + } + } + + [self setSavedSelection: nil]; + + if (inRefresh && savedLastRow > -1) + [aTableView scrollRowToVisible: savedLastRow]; + } +} + +- (NSSize)minSize +{ + NSArray *tableColumns; + NSRect headerRect; + NSTableColumn *column; + float minHeight, minWidth, rowHeight, scrollHeight, scrollWidth; + int numRows; + + [LiLog logAsDebug: @"[FileTableDelegate minSize]"]; + [LiLog indentDebugLog]; + + headerRect = [[[self tableView] headerView] frame]; + logRect(@"headerRect", headerRect); + + rowHeight = [[self tableView] rowHeight]; + [LiLog logAsDebug: @"row height: %f", rowHeight]; + numRows = [self numberOfRowsInTableView: [self tableView]]; + [LiLog logAsDebug: @"number of rows: %d", numRows]; + + scrollWidth = 17.0; + scrollHeight = 34.0; + + tableColumns = [[self tableView] tableColumns]; + minWidth = scrollWidth; + [LiLog indentDebugLog]; + for (column in tableColumns) { + float colWidth; + + colWidth = [column width]; + [LiLog logAsDebug: @"colWidth: %f", colWidth]; + minWidth += colWidth; + } + [LiLog unindentDebugLog]; + [LiLog logAsDebug: @"minWidth: %f", minWidth]; + + minHeight = headerRect.size.height + rowHeight * numRows + scrollHeight; + [LiLog logAsDebug: @"minHeight: %f", minHeight]; + + [LiLog unindentDebugLog]; + return NSMakeSize(minWidth, minHeight); +} + + +- (BOOL)validateAction: (SEL)anAction +{ + //[LiLog logAsDebug: @"[FileTableDelegate validateAction: %@]", NSStringFromSelector(anAction)]; + if (anAction == @selector(addFiles:)) { + return [[self fileStore] isEditable]; + } else if (anAction == @selector(delete:)) { + return ([[self fileStore] isEditable] && + [tableView numberOfSelectedRows] > 0); + } else if (anAction == @selector(revealInFinder:)) { + return ([[self fileStore] isEditable] && + [tableView numberOfSelectedRows] > 0); + } else if (anAction == @selector(openSelectedFiles:)) { + return ([[self fileStore] isEditable] && + [tableView numberOfSelectedRows] > 0); + } else + return YES; +} + +- (BOOL)validateMenuItem: (NSMenuItem *)anItem +{ + return [self validateAction: [anItem action]]; +} + +- (void)redisplay +{ + NSString *filePlural; + unsigned long numRecords; + + [self setSearchString: [self searchString]]; + [self setSelectedColumn: [self selectedColumn]]; + + numRecords = [[self sortedList] count]; + if (numRecords == 1) { + filePlural = myLocalizedString(@"LiFileSingular"); + } else { + filePlural = myLocalizedString(@"LiFilePlural"); + } + [statusLine setStringValue: + [NSString stringWithFormat: @"(%d %@)", numRecords, filePlural]]; + + [tableView reloadData]; +} +@synthesize statusLine; +@synthesize theTableColumns; +@synthesize theFileStore; +@synthesize theListPrefs; +@synthesize isAscending; +@synthesize tableView; +@synthesize theContextMenu; +@synthesize theFilter; +@synthesize theSavedSelection; +@synthesize theShownColumns; +@synthesize theSelectedColumn; +@synthesize inspectorController; +@synthesize theSearchString; +@end + +@implementation FileTableDelegate (CommonAccessors) +#if 0 +- (NSString *)group +{ + return [self filterForAttribute: LiGroupsAttribute]; +} + +- (void)setGroup: (NSString *)aGroupName +{ + if (aGroupName == nil) { + if ([self group] != nil) { + NSDictionary *filter; + + filter = [NSDictionary dictionaryWithObject: [self group] + forKey: LiGroupsAttribute]; + [self removeAttributeFilters: filter]; + } + } else { + NSDictionary *filter; + + filter = [NSDictionary dictionaryWithObject: aGroupName + forKey: LiGroupsAttribute]; + [self addAttributeFilters: filter]; + } + // We're re-filtering. + [self setActiveList: nil]; + + [self redisplay]; +} +#endif + +- (NSString *)group +{ + return [[self filter] value]; +} + +- (void)setGroup: (NSString *)aGroup +{ + LiFilter *filter; + + if (aGroup != nil) + filter = [LiFilter filterWithAttribute: LiGroupsAttribute + compareSelector: @selector(isEqual:) + value: aGroup]; + else + filter = nil; + [self setFilter: filter]; +} +@end + +@implementation FileTableDelegate (Accessors) +- (LiFileStore *)fileStore +{ + return theFileStore; +} + +- (void)setFileStore: (LiFileStore *)aFileStore +{ + [LiLog logAsDebug: @"[FileTableDelegate setFileStore: %@]", aFileStore]; + + if (aFileStore != theFileStore) { + NSNotificationCenter *defaultCenter; + + defaultCenter = [NSNotificationCenter defaultCenter]; + if (theFileStore != nil) { + [defaultCenter removeObserver: self + name: LiFileChangedNotification + object: theFileStore]; + [theFileStore release]; + } + if (aFileStore != nil) { + [defaultCenter addObserver: self + selector: @selector(respondToFileChanged:) + name: LiFileChangedNotification + object: aFileStore]; + theFileStore = [aFileStore retain]; + } + } +} + +#if 0 +- (NSMutableDictionary *)attributeFilters +{ + return theFilters; +} + +- (void)setAttributeFilters: (NSMutableDictionary *)someFilters +{ + if (someFilters != theFilters) { + [someFilters retain]; + [theFilters release]; + theFilters = someFilters; + } +} +#endif + +- (LiFilter *)filter +{ + return theFilter; +} + +- (void)setFilter: (LiFilter *)aFilter +{ + [aFilter retain]; + [theFilter retain]; + theFilter = aFilter; +} + +- (NSMutableDictionary *)shownColumns +{ + return theShownColumns; +} + +- (void)setShownColumns: (NSMutableDictionary *)someColumns +{ + [someColumns retain]; + [theShownColumns release]; + theShownColumns = someColumns; +} + +- (NSArray *)sortedList +{ + if (theSortedList == nil) + return [self activeList]; + else + return theSortedList; +} + +- (void)setSortedList: (NSArray *)aFileList +{ + [aFileList retain]; + [theSortedList release]; + theSortedList = aFileList; +} + +- (NSArray *)activeList +{ + if (theActiveList == nil) + return [self fileList]; + else + return theActiveList; +} + +- (void)setActiveList: (NSArray *)aFileList +{ + if (aFileList != theActiveList) { + [aFileList retain]; + [theActiveList release]; + theActiveList = aFileList; + + [self setSortedList: nil]; + } +} + +- (NSArray *)fileList +{ + return [[self fileStore] filesMatchingFilter: [self filter]]; +} + +- (NSString *)searchString +{ + return theSearchString; +} + +- (NSArray *)filter: (NSArray *)aFileList + byString: (NSString *)aSearchString +{ + LiFileHandle *record; + NSMutableArray *subset; + + if ([aSearchString length] == 0) + return aFileList; + + subset = [NSMutableArray array]; + for (record in aFileList) { + NSString *filename; + NSRange range; + + filename = [[record filename] lowercaseString]; + range = [filename rangeOfString: aSearchString]; + if (range.location != NSNotFound) + [subset addObject: record]; + } + + return subset; +} + +- (void)setSearchString: (NSString *)aSearchString +{ + NSArray *tmpList; + + if (aSearchString == nil) { + aSearchString = @""; + tmpList = [self fileList]; + } else if ([aSearchString rangeOfString: theSearchString options: NSCaseInsensitiveSearch].location != NSNotFound) { + // Optimized filter - only need to select off the active list. + tmpList = [self filter: [self activeList] byString: aSearchString]; + } else { + tmpList = [self filter: [self fileList] byString: aSearchString]; + } + + [aSearchString retain]; + [theSearchString release]; + theSearchString = aSearchString; + + [self setActiveList: tmpList]; +} + +- (NSTableColumn *)selectedColumn +{ + return theSelectedColumn; +} + +- (void)setSelectedColumn: (NSTableColumn *)aColumn +{ + LiBrowserColumn *col; + struct SortContext context; + + col = [self columnForIdentifier: [aColumn identifier]]; + + context.ascending = isAscending; + context.getMethod = [col getMethod]; + context.compareMethod = [col compareMethod]; + [self setSelectedColumn: aColumn withContext: &context]; +} + +- (void)setSelectedColumn: (NSTableColumn *)aColumn + withContext: (void *)someContext +{ + struct SortContext *context; + NSArray *sortedList; + + [aColumn retain]; + [theSelectedColumn release]; + theSelectedColumn = aColumn; + + context = (struct SortContext *)someContext; + + if ([tableView highlightedTableColumn] != theSelectedColumn) { + [tableView setIndicatorImage: nil + inTableColumn: [tableView highlightedTableColumn]]; + } + + [tableView setHighlightedTableColumn: theSelectedColumn]; + if (theSelectedColumn != nil) { + if (context->ascending) + [tableView setIndicatorImage: ascendingSortingImage + inTableColumn: theSelectedColumn]; + else + [tableView setIndicatorImage: descendingSortingImage + inTableColumn: theSelectedColumn]; + + sortedList = [[self activeList] sortedArrayUsingFunction: contextSorter + context: someContext]; + + [self setSortedList: sortedList]; + } else { + [self setSortedList: nil]; + } +} + +- (NSMutableSet *)savedSelection +{ + return theSavedSelection; +} + +- (void)setSavedSelection: (NSMutableSet *)aSelection +{ + [aSelection retain]; + [theSavedSelection release]; + theSavedSelection = aSelection; +} + +- (NSMutableDictionary *)listPrefs +{ + if (theListPrefs == nil) { + NSDictionary *listPrefs; + + listPrefs = [[Preferences sharedPreferences] fileListPrefs]; + if (listPrefs != nil) { + theListPrefs = [[NSMutableDictionary alloc] initWithDictionary: listPrefs]; + } else + theListPrefs = [[NSMutableDictionary alloc] init]; + } + return theListPrefs; +} + +- (void)setListPrefs: (NSMutableDictionary *)listPrefs +{ + [listPrefs retain]; + [theListPrefs release]; + theListPrefs = listPrefs; + + [[Preferences sharedPreferences] setFileListPrefs: theListPrefs]; +} + +- (NSMutableDictionary *)columnPrefsForIdentifier: (NSString *)anIdentifier +{ + NSMutableDictionary *colPrefs, *retVal; + + colPrefs = [[self listPrefs] objectForKey: @"columns"]; + if (colPrefs == nil) { + colPrefs = [NSMutableDictionary dictionary]; + [[self listPrefs] setObject: colPrefs forKey: @"columns"]; + } + + retVal = [colPrefs objectForKey: anIdentifier]; + if (retVal == nil) { + retVal = [NSMutableDictionary dictionary]; + [colPrefs setObject: retVal forKey: anIdentifier]; + } + + return retVal; +} + +- (void)setColumnPrefs: (NSMutableDictionary *)columnPrefs + forIdentifier: (NSString *)anIdentifier +{ + NSMutableDictionary *colPrefs; + + colPrefs = [[self listPrefs] objectForKey: @"columns"]; + if (colPrefs == nil) { + colPrefs = [NSMutableDictionary dictionary]; + [[self listPrefs] setObject: colPrefs forKey: @"columns"]; + } + + [colPrefs setObject: columnPrefs forKey: anIdentifier]; + + [[Preferences sharedPreferences] setFileListPrefs: theListPrefs]; +} + +- (NSTableView *)tableView +{ + return tableView; +} +@end + +@implementation LiFileHandle (GUIStuff) +- (void)revealInFinder +{ + NSURL *fileURL; + + fileURL = [self url]; + if ([fileURL isFileURL]) { + [[NSWorkspace sharedWorkspace] selectFile: + [fileURL path] inFileViewerRootedAtPath: @""]; + } +} +@end \ No newline at end of file -- cgit v1.2.3