#import #import #import #import #import #import #import "GNUstep.h" NSComparisonResult sortingWithProperty(id record1, id record2, void *context) { NSString *property = (NSString *) context; id value1 = [(CKRecord *) record1 valueForProperty: property]; id value2 = [(CKRecord *) record2 valueForProperty: property]; if ((value1) && (value2)) { return [value1 compare: value2]; } else if ((value1 == nil) && (value2)) { return NSOrderedDescending; } else if ((value1) && (value2 == nil)) { return NSOrderedAscending; } else { return NSOrderedSame; } } NSComparisonResult reverseSortingWithProperty(id record1, id record2, void *context) { NSComparisonResult result = sortingWithProperty(record1, record2, context); switch(result) { case NSOrderedAscending: return NSOrderedDescending; case NSOrderedDescending: return NSOrderedAscending; default: return NSOrderedSame; } } @implementation CKCollectionView /** Private **/ - (void) buildInternalCache { /* Do not rebuild if it is editing */ if (isEditing == YES) return; CREATE_AUTORELEASE_POOL(x); [internalCache removeAllObjects]; if (root == nil) { [internalCache setArray: [collection items]]; } else if ([root isKindOfClass: [CKGroup class]]) { CKGroup *group = (CKGroup *) root; [internalCache addObjectsFromArray: [group items]]; } else if ([root isKindOfClass: [NSArray class]]) { NSEnumerator *e = [(NSArray *) root objectEnumerator]; CKGroup *group; while ((group = [e nextObject])) { [internalCache addObjectsFromArray: [collection itemsUnderGroup: group]]; } } else { NSLog(@"Error: unknown root %@", root); } if (searchElement != nil) { /* Remove unmatched item */ int i; for (i = 0; i < [internalCache count]; i++) { CKRecord *record = [internalCache objectAtIndex: i]; if ([searchElement matchesRecord: record] == NO) { [internalCache removeObjectAtIndex: i]; i--; } } } if (sortingProperty) { /* Always keep sorted */ [self sortWithProperty: sortingProperty reverse: reverseSorting]; } DESTROY(x); } - (void) handleCollectionChanged: (NSNotification *) not { [self buildInternalCache]; } /** End of private **/ - (id) initWithFrame: (NSRect) frame { self = [super initWithFrame: frame]; displaySubgroup = NO; displayItemsInSubgroup = NO; isEditing = NO; internalCache = [[NSMutableArray alloc] init]; NSTableColumn *tvc = [(NSTableColumn *)[NSTableColumn alloc] initWithIdentifier: kCKUIDProperty]; [[tvc headerCell] setStringValue: _(kCKUIDProperty)]; [tvc setWidth: 200]; [tvc setMinWidth: 100]; NSRect rect = frame; tableScrollView = [[NSScrollView alloc] initWithFrame: rect]; [tableScrollView setBorderType: NSBezelBorder]; [tableScrollView setHasVerticalScroller: YES]; [tableScrollView setHasHorizontalScroller: YES]; [tableScrollView setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable]; rect.size = [tableScrollView contentSize]; tableView = [[CKTableView alloc] initWithFrame: rect]; [tableView setDataSource: self]; [tableView addTableColumn: tvc]; [tableView setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable]; [tableScrollView setDocumentView: tableView]; [self addSubview: tableScrollView]; [tvc sizeToFit]; [tvc setResizable: YES]; [tableView setAutoresizesAllColumnsToFit: YES]; [tableView sizeLastColumnToFit]; RELEASE(tableScrollView); RELEASE(tableView); RELEASE(tvc); /* Listen to collection change */ [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleCollectionChanged:) name: CKCollectionChangedNotification object: nil]; return self; } - (void) dealloc { DESTROY(collection); DESTROY(root); DESTROY(displayProperties); DESTROY(displaySubgroupProperty); DESTROY(internalCache); DESTROY(sortingProperty); [super dealloc]; } - (id) itemAtIndex: (int) index { return [internalCache objectAtIndex: index]; } - (int) numberOfItems { return [internalCache count]; } /* Data source */ - (int) numberOfRowsInTableView: (NSTableView *) tv { if ((collection == nil) || (tv != tableView)) { return 0; } return [internalCache count]; } - (id) tableView: (NSTableView *) tv objectValueForTableColumn: (NSTableColumn *) tc row: (int) rowIndex { if ((collection == nil) || (tv != tableView)) { return nil; } id item = [self itemAtIndex: rowIndex]; if ([item isKindOfClass: [CKItem class]]) { return [(CKItem *) item valueForProperty: [tc identifier]]; } else if ([item isKindOfClass: [CKGroup class]]) { return [(CKGroup *) item valueForProperty: displaySubgroupProperty]; } return nil; } /* Accessories */ - (void) setDisplayProperties: (NSArray *) keys { // array of property keys ASSIGNCOPY(displayProperties, keys); /* remove extra */ while ([[tableView tableColumns] count] > [displayProperties count]) { [tableView removeTableColumn: [[tableView tableColumns] lastObject]]; } /* reset identifier and add extra */ int i; NSTableColumn *tc; NSString *key; for (i = 0; i < [displayProperties count]; i++) { NSArray *tcs = [tableView tableColumns]; key = [displayProperties objectAtIndex: i]; if (i < [tcs count]) { tc = [tcs objectAtIndex: i]; [tc setIdentifier: key]; [[tc headerCell] setStringValue: _(key)]; } else { /* Create new one */ tc = [(NSTableColumn *)[NSTableColumn alloc] initWithIdentifier: key]; [[tc headerCell] setStringValue: _(key)]; [tc setWidth: 200]; [tc setMinWidth: 100]; [tc setResizable: YES]; [tableView addTableColumn: tc]; RELEASE(tc); } } [tableView sizeToFit]; [tableView sizeLastColumnToFit]; } - (NSArray *) displayProperties { return displayProperties; } - (void) reloadData { [tableView reloadData]; } - (void) beginEditing { isEditing = YES; } - (void) endEditing { isEditing = NO; [self buildInternalCache]; } - (void) setCollection: (CKCollection *) s { ASSIGN(collection, s); [self buildInternalCache]; } - (CKCollection *) collection { return collection; } - (CKTableView *) tableView { return tableView; } - (void) setRoot: (id) r { ASSIGN(root, r); [self buildInternalCache]; } - (id) root { return root; } - (void) setSearchElement: (CKSearchElement *) element { ASSIGN(searchElement, element); [self buildInternalCache]; } - (CKSearchElement *) searchElement { return searchElement; } - (void) setDisplaySubgroup: (BOOL) b { displaySubgroup = b; [self buildInternalCache]; } - (BOOL) isDisplaySubgroup { return displaySubgroup; } - (void) setDisplayItemsInSubgroup: (BOOL) b { displayItemsInSubgroup = b; [self buildInternalCache]; } - (BOOL) isDisplayItemsInSubgroup { return displayItemsInSubgroup; } - (void) setDisplaySubgroupProperty: (id) p { ASSIGNCOPY(displaySubgroupProperty, p); } - (id) displaySubgroupProperty { return displaySubgroupProperty; } - (void) sortWithProperty: (NSString *) property reverse: (BOOL) reverse { if (reverse == NO) [internalCache sortUsingFunction: sortingWithProperty context: property]; else [internalCache sortUsingFunction: reverseSortingWithProperty context: property]; } - (void) setSortingProperty: (NSString *) property reverse: (BOOL) reverse { reverseSorting = reverse; ASSIGN(sortingProperty, property); } @end @implementation CKTableView @end