source: releases/Pester/1.1b4/Source/NJRTableDelegate.m

Last change on this file was 53, checked in by Nicholas Riley, 21 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.