source: trunk/Cocoa/Pester/Source/NJRTableDelegate.m@ 306

Last change on this file since 306 was 53, checked in by Nicholas Riley, 22 years ago

Updated for Pester 1.1a5 (very limited release).

Pester 1.1a4 was never released.

File size: 8.9 KB
Line 
1//
2// NJRTableDelegate.m
3// Pester
4//
5// Created by Nicholas Riley on Sun Oct 27 2002.
6// Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "NJRTableDelegate.h"
10#import "NSTableView-NJRExtensions.h"
11
12#pragma mark sorting support
13
14typedef struct { NSString *key; BOOL descending; } SortContext;
15
16// Sort array of itemNums, by looking up the itemNum in the dictionary of objects.
17// based on code of Ondra Cada <ocs@ocs.cz> on cocoa-dev list
18
19int ORDER_BY_CONTEXT(id left, id right, void *ctxt) {
20 SortContext *context = (SortContext *)ctxt;
21 int order = 0;
22 id key = context->key;
23 if (0 != key) {
24 id first, second; // the actual objects to compare
25
26 if (context->descending) {
27 first = [right valueForKey: key];
28 second = [left valueForKey: key];
29 } else {
30 first = [left valueForKey: key];
31 second = [right valueForKey: key];
32 }
33
34 if ([first respondsToSelector: @selector(caseInsensitiveCompare:)]) {
35 order = [first caseInsensitiveCompare:second];
36 } else { // sort numbers or dates
37 order = [(NSNumber *)first compare:second];
38 }
39 }
40 return order;
41}
42
43@interface NJRTableDelegate (Private)
44
45- (void)_positionTypeSelectDisplay;
46- (void)_sortByColumn:(NSTableColumn *)inTableColumn;
47
48@end
49
50@implementation NJRTableDelegate
51
52#pragma mark initialize-release
53
54- (void)awakeFromNib;
55{
56 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_positionTypeSelectDisplay) name: NSViewFrameDidChangeNotification object: tableView];
57}
58
59- (void)dealloc
60{
61 [[NSNotificationCenter defaultCenter] removeObserver: self];
62 [sortingColumn release];
63 [sortingKey release];
64 [reorderedData release];
65 [super dealloc];
66}
67
68#pragma mark accessing
69
70- (void)setSortingColumn:(NSTableColumn *)inNewValue;
71{
72 [inNewValue retain];
73 [sortingColumn release];
74 sortingColumn = inNewValue;
75}
76
77- (void)setSortingKey:(NSString *)inNewValue;
78{
79 [inNewValue retain];
80 [sortingKey release];
81 sortingKey = inNewValue;
82}
83
84#pragma mark sorting
85
86- (NSString *)_sortContextDefaultKey;
87{
88 NSString *autosaveName = [tableView autosaveName];
89 if (autosaveName != nil)
90 return [NSString stringWithFormat: @"NJRTableDelegate SortContext %@", autosaveName];
91 else
92 return nil;
93}
94
95- (void)_sortData;
96{
97 SortContext ctxt = { sortingKey, sortDescending };
98 NSString *sortContextKey = [self _sortContextDefaultKey];
99
100 if (sortContextKey != nil) {
101 [[NSUserDefaults standardUserDefaults] setObject:
102 [NSDictionary dictionaryWithObjectsAndKeys: sortingKey, @"sortingKey", [NSNumber numberWithBool: sortDescending], @"sortDescending", nil]
103 forKey: [self _sortContextDefaultKey]];
104 }
105
106 // sort the NSMutableArray
107 [reorderedData sortUsingFunction: ORDER_BY_CONTEXT context: &ctxt];
108 [tableView reloadData];
109}
110
111- (void)_sortByColumn:(NSTableColumn *)inTableColumn;
112{
113 NSSet *oldSelection = [self selectedItems];
114 if (sortingColumn == inTableColumn) {
115 // User clicked same column, change sort order
116 sortDescending = !sortDescending;
117 // Possible optimization: Don't actually re-sort if you just change the sorting direction; instead, just display either the nth item or the (count-1-n)th item depending on ascending/descending.)
118 } else {
119 // User clicked new column, change old/new column headers, save new sorting column, and re-sort the array.
120 if (sortingColumn != nil) {
121 [tableView setIndicatorImage: nil inTableColumn: sortingColumn];
122 sortDescending = NO; // on initial sort, preserve previous sort order
123 }
124 [self setSortingKey: [inTableColumn identifier]];
125 [self setSortingColumn: inTableColumn];
126 [tableView setHighlightedTableColumn: inTableColumn];
127 }
128 [tableView setIndicatorImage: (sortDescending ? [NSTableView descendingSortIndicator] : [NSTableView ascendingSortIndicator]) inTableColumn: inTableColumn];
129 [self _positionTypeSelectDisplay];
130 // Actually sort the data
131 [self _sortData];
132 [self selectItems: oldSelection];
133}
134
135- (void)_initialSortData;
136{
137 NSString *sortContextKey = [self _sortContextDefaultKey];
138 NSDictionary *sortContext;
139 NSString *key;
140 NSTableColumn *column;
141
142 if (sortContextKey == nil) goto noContext;
143 if ( (sortContext = [[NSUserDefaults standardUserDefaults] dictionaryForKey: sortContextKey]) == nil) goto noContext;
144 if ( (key = [sortContext objectForKey: @"sortingKey"]) == nil) goto noContext;
145 if ( (column = [tableView tableColumnWithIdentifier: key]) == nil) goto noContext;
146 sortDescending = [[sortContext objectForKey: @"sortDescending"] boolValue];
147 [self _sortByColumn: column];
148 return;
149
150noContext:
151 sortDescending = NO;
152 [self _sortByColumn: [[tableView tableColumns] objectAtIndex: 0]];
153}
154
155- (NSMutableArray *)reorderedDataForData:(NSArray *)data;
156{
157 if (reorderedData == nil) {
158 reorderedData = [data mutableCopy];
159 [self _initialSortData];
160 } else {
161 NSSet *oldSelection = [self selectedItems];
162 [reorderedData release]; reorderedData = nil;
163 reorderedData = [data mutableCopy];
164 [self _sortData];
165 [self selectItems: oldSelection];
166 }
167 return reorderedData;
168}
169
170#pragma mark type selection
171
172- (void)_positionTypeSelectDisplay;
173{
174 [tableView resetTypeSelect]; // avoid extraneous matching
175 if ([tableView typeSelectDisplay] != nil && sortingColumn != nil) {
176 NSControl *typeSelectControl = [tableView typeSelectDisplay];
177 if ([typeSelectControl isKindOfClass: [NSControl class]]) {
178 NSView *superview = [typeSelectControl superview];
179 NSRect columnRect = [superview convertRect: [tableView rectOfColumn: [tableView columnWithIdentifier: sortingKey]] fromView: tableView];
180 // XXX support horizontal scroll bar/clipping (not for Pester, but eventually)
181 // NSRect tableScrollFrame = [[tableView enclosingScrollView] frame];
182 NSRect selectFrame = [typeSelectControl frame];
183 [superview setNeedsDisplayInRect: selectFrame]; // fix artifacts caused by moving view
184 selectFrame.origin.x = columnRect.origin.x;
185 selectFrame.size.width = columnRect.size.width;
186 [typeSelectControl setAlignment: [[sortingColumn dataCell] alignment]];
187 [typeSelectControl setFrame: selectFrame];
188 }
189 }
190}
191
192#pragma mark saving/restoring selection
193
194- (NSSet *)selectedItems;
195{
196 NSMutableSet *result = [NSMutableSet set];
197 NSEnumerator *e = [tableView selectedRowEnumerator];
198 NSNumber *rowNum;
199
200 while ( (rowNum = [e nextObject]) != nil) {
201 id item = [reorderedData objectAtIndex: [rowNum intValue]];
202 [result addObject: item];
203 }
204 return result;
205}
206
207- (void)selectItems:(NSSet *)inSelectedItems;
208{
209 NSEnumerator *e = [inSelectedItems objectEnumerator];
210 id item;
211 int savedLastRow = 0;
212
213 [tableView deselectAll: nil];
214
215 while ( (item = [e nextObject]) != nil ) {
216 int row = [reorderedData indexOfObjectIdenticalTo: item];
217 if (row != NSNotFound) {
218 [tableView selectRow: row byExtendingSelection: YES];
219 savedLastRow = row;
220 }
221 }
222 [tableView scrollRowToVisible: savedLastRow];
223}
224
225@end
226
227@implementation NJRTableDelegate (NJRTableViewDelegate)
228
229- (void)tableView:(NSTableView *)aTableView didClickTableColumn:(NSTableColumn *)inTableColumn
230{
231 [[tableView window] makeFirstResponder: aTableView];
232 [self _sortByColumn: inTableColumn];
233}
234
235- (void)tableViewColumnDidResize:(NSNotification *)notification;
236{
237 [self _positionTypeSelectDisplay];
238}
239
240- (void)tableViewColumnDidMove:(NSNotification *)notification;
241{
242 [self _positionTypeSelectDisplay];
243}
244
245- (void)tableView:(NSTableView *)aTableView selectRowMatchingString:(NSString *)matchString;
246{
247 // Look for a highlighted column, presuming we are sorted by that column, and search its values.
248 NSTableColumn *col = [aTableView highlightedTableColumn];
249 id dataSource = [aTableView dataSource];
250 int i, rowCount = [reorderedData count];
251 if (nil == col) return;
252 if (sortDescending) {
253 for ( i = rowCount - 1 ; i >= 0 ; i-- ) {
254 NSComparisonResult order = [matchString caseInsensitiveCompare:
255 [dataSource tableView: aTableView objectValueForTableColumn: col row: i]];
256 if (order != NSOrderedDescending) break;
257 }
258 if (i < 0) i = 0;
259 } else {
260 for ( i = 0 ; i < rowCount ; i++ ) {
261 NSComparisonResult order = [matchString caseInsensitiveCompare:
262 [dataSource tableView: aTableView objectValueForTableColumn: col row: i]];
263 if (order != NSOrderedDescending) break;
264 }
265 if (i >= rowCount) i = rowCount - 1;
266 }
267 // Now select row i -- either the one we found, or the first/last row if not found.
268 [aTableView selectRow: i byExtendingSelection: NO];
269 [aTableView scrollRowToVisible: i];
270}
271
272@end
Note: See TracBrowser for help on using the repository browser.