ReconTableView.m (7716B)
1 // 2 // ReconTableView.m 3 // Unison 4 // 5 // Created by Trevor Jim on Wed Aug 27 2003. 6 // Copyright (c) 2003, 2016. See file COPYING for details. 7 // 8 9 #import "ReconTableView.h" 10 #import "ReconItem.h" 11 #import "MyController.h" 12 13 @implementation NSOutlineView (_UnisonExtras) 14 15 - (NSArray *)selectedObjects 16 { 17 NSMutableArray *result = [NSMutableArray array]; 18 NSIndexSet *set = [self selectedRowIndexes]; 19 NSUInteger index = [set firstIndex]; 20 while (index != NSNotFound) { 21 [result addObject:[self itemAtRow:index]]; 22 index = [set indexGreaterThanIndex: index]; 23 } 24 return result; 25 } 26 27 - (void)setSelectedObjects:(NSArray *)selectedObjects 28 { 29 NSMutableIndexSet *set = [NSMutableIndexSet indexSet]; 30 NSUInteger i = [selectedObjects count]; 31 while (i--) { 32 NSInteger index = [self rowForItem:[selectedObjects objectAtIndex:i]]; 33 if (index >= 0) [set addIndex:index]; 34 } 35 [self selectRowIndexes:set byExtendingSelection:NO]; 36 } 37 38 - (NSEnumerator *)selectedObjectEnumerator 39 { 40 return [[self selectedObjects] objectEnumerator]; 41 } 42 43 - (int)rowCapacityWithoutScrolling 44 { 45 float bodyHeight = [self visibleRect].size.height; 46 bodyHeight -= [[self headerView] visibleRect].size.height; 47 return bodyHeight / ([self rowHeight] + 2.0); 48 } 49 50 - (BOOL)_canAcceptRowCountWithoutScrolling:(NSInteger)rows 51 { 52 return ([self numberOfRows] + rows) <= [self rowCapacityWithoutScrolling]; 53 } 54 55 - (BOOL)_expandChildrenIfSpace:(id)parent level:(int)level 56 { 57 BOOL didExpand = NO; 58 id dataSource = [self dataSource]; 59 NSInteger count = [dataSource outlineView:self numberOfChildrenOfItem:parent]; 60 if (level == 0) { 61 if (count && ([self isItemExpanded:parent] || [self _canAcceptRowCountWithoutScrolling:count])) { 62 [self expandItem:parent expandChildren:NO]; 63 didExpand = YES; 64 } 65 } else { 66 // try expanding each of our children. If all expand, then return YES, 67 // indicating that it may be worth trying the next level 68 int i; 69 for (i=0; i < count; i++) { 70 id child = [dataSource outlineView:self child:i ofItem:parent]; 71 didExpand = [self _expandChildrenIfSpace:child level:level-1] || didExpand; 72 } 73 } 74 75 return didExpand; 76 } 77 78 - (void)expandChildrenIfSpace 79 { 80 int level = 1; 81 while ([self _expandChildrenIfSpace:nil level:level]) level++; 82 } 83 84 @end 85 86 @implementation ReconTableView 87 88 - (BOOL)editable 89 { 90 return editable; 91 } 92 93 - (void)setEditable:(BOOL)x 94 { 95 editable = x; 96 } 97 98 - (BOOL)validateItem:(SEL) action 99 { 100 if (action == @selector(selectAll:) 101 || action == @selector(selectConflicts:) 102 || action == @selector(copyLR:) 103 || action == @selector(copyRL:) 104 || action == @selector(leaveAlone:) 105 || action == @selector(forceNewer:) 106 || action == @selector(forceOlder:) 107 || action == @selector(revert:) 108 || action == @selector(ignorePath:) 109 || action == @selector(ignoreExt:) 110 || action == @selector(ignoreName:)) 111 return editable; 112 else if (action == @selector(merge:)) { 113 if (!editable) return NO; 114 else return [self canDiffSelection]; 115 } 116 else if (action == @selector(showDiff:)) { 117 if ((!editable) || (!([self numberOfSelectedRows]==1))) 118 return NO; 119 else return [self canDiffSelection]; 120 } 121 else return YES; 122 } 123 124 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem 125 { 126 return [self validateItem:[menuItem action]]; 127 } 128 129 - (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem 130 { 131 return [self validateItem:[toolbarItem action]]; 132 } 133 134 - (void)doIgnore:(unichar)c 135 { 136 NSEnumerator *e = [self selectedObjectEnumerator]; 137 ReconItem *item, *last = nil; 138 while (item = [e nextObject]) { 139 [item doIgnore:c]; 140 last = item; 141 } 142 if (last) { // something was selected 143 MyController* controller = (MyController*) [self dataSource]; 144 last = [controller updateForIgnore:last]; 145 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:[self rowForItem:last]] byExtendingSelection:NO]; 146 [self reloadData]; 147 } 148 } 149 150 - (IBAction)ignorePath:(id)sender 151 { 152 [self doIgnore:'I']; 153 } 154 155 - (IBAction)ignoreExt:(id)sender 156 { 157 [self doIgnore:'E']; 158 } 159 160 - (IBAction)ignoreName:(id)sender 161 { 162 [self doIgnore:'N']; 163 } 164 165 - (void)doAction:(unichar)c 166 { 167 int numSelected = 0; 168 NSEnumerator *e = [self selectedObjectEnumerator]; 169 ReconItem *item, *last = nil; 170 while (item = [e nextObject]) { 171 numSelected++; 172 [item doAction:c]; 173 last = item; 174 } 175 if (numSelected>0) { 176 long nextRow = [self rowForItem:last] + 1; 177 if (numSelected == 1 && [self numberOfRows] > nextRow && c!='d') { 178 // Move to next row, unless already at last row, or if more than one row selected 179 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:nextRow] byExtendingSelection:NO]; 180 [self scrollRowToVisible:nextRow]; 181 } 182 [self reloadData]; 183 } 184 } 185 186 - (IBAction)copyLR:(id)sender 187 { 188 [self doAction:'>']; 189 } 190 191 - (IBAction)copyRL:(id)sender 192 { 193 [self doAction:'<']; 194 } 195 196 - (IBAction)leaveAlone:(id)sender 197 { 198 [self doAction:'/']; 199 } 200 201 - (IBAction)forceOlder:(id)sender 202 { 203 [self doAction:'-']; 204 } 205 206 - (IBAction)forceNewer:(id)sender 207 { 208 [self doAction:'+']; 209 } 210 211 - (IBAction)selectConflicts:(id)sender 212 { 213 [self deselectAll:self]; 214 MyController* controller = (MyController*) [self dataSource]; 215 NSMutableArray *reconItems = [controller reconItems]; 216 int i = 0; 217 for (; i < [reconItems count]; i++) { 218 ReconItem *item = [reconItems objectAtIndex:i]; 219 if ([item isConflict]) 220 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:[self rowForItem:item]] byExtendingSelection:YES]; 221 } 222 } 223 224 - (IBAction)revert:(id)sender 225 { 226 [self doAction:'R']; 227 } 228 229 - (IBAction)merge:(id)sender 230 { 231 [self doAction:'m']; 232 } 233 234 - (IBAction)showDiff:(id)sender 235 { 236 [self doAction:'d']; 237 } 238 239 /* There are menu commands for these, but we add some shortcuts so you don't 240 have to press the Command key */ 241 - (void)keyDown:(NSEvent *)event 242 { 243 /* some keys return zero-length strings */ 244 if ([[event characters] length] == 0) { 245 [super keyDown:event]; 246 return; 247 } 248 249 /* actions are disabled when when menu items are */ 250 if (!editable) { 251 [super keyDown:event]; 252 return; 253 } 254 255 unichar c = [[event characters] characterAtIndex:0]; 256 switch (c) { 257 case '>': 258 case NSRightArrowFunctionKey: 259 [self doAction:'>']; 260 break; 261 case '<': 262 case NSLeftArrowFunctionKey: 263 [self doAction:'<']; 264 break; 265 case '?': 266 case '/': 267 [self doAction:'/']; 268 break; 269 default: 270 [super keyDown:event]; 271 break; 272 } 273 } 274 275 - (BOOL)canDiffSelection 276 { 277 BOOL canDiff = YES; 278 NSEnumerator *e = [self selectedObjectEnumerator]; 279 ReconItem *item; 280 while (item = [e nextObject]) { 281 if (![item canDiff]) canDiff= NO; 282 } 283 return canDiff; 284 } 285 286 /* Override default highlight colour because it's hard to see the 287 conflict/resolution icons */ 288 - (id)_highlightColorForCell:(NSCell *)cell 289 { 290 if(([[self window] firstResponder] == self) && 291 [[self window] isMainWindow] && 292 [[self window] isKeyWindow]) 293 294 return [NSColor colorWithCalibratedRed:0.7 green:0.75 blue:0.8 alpha:1.0]; 295 else return [NSColor colorWithCalibratedRed:0.8 green:0.8 blue:0.8 alpha:1.0]; 296 } 297 298 @end